I am trying to extract id from the below array of objects and so far I am able to give it a go with the below code but it is showing undefined and cannot get id , would you please check the code and adjust to get id out?
const array = [{
contact: {
id: 1,
email: 'roar#gmail.com',
},
date: '2/4/22'
},
{
contact: {
id: 2,
email: 'grr#gmail.com',
},
date: '2/4/22'
}
]
function extractValue(arr, prop) {
let extractedValue = [];
for (let i = 0; i < arr.length; ++i) {
// extract value from property
extractedValue.push(arr[i][prop]);
}
return extractedValue;
}
const result = extractValue(array, 'contact.id');
console.log(result);
A good way to do this is the Array Map method
This will get all the id's from your array
const result = array.map((val) => val.contact.id)
const extractValue = (array, path) => {
const [first, second] = path.split('.')
if (second) return array.map(obj => obj[first][second])
return array.map(obj => obj[first])
}
const res = extractValue(array, 'contact.id')
console.log(res)
// => [ 1, 2 ]
this will support single and double level nested results
function find(val, arr) {
for (let x of arr)
val = val[x];
return val;
}
function extractValue(arr, prop) {
return array.map(x => find(x, prop.split(".")))
}
Related
I want to convert an object into an array of object but my code give the wrong result like shown below..
// object
data = { user_id : '123' }
// expected result
data = [ { user_id : '123' } ]
// what I get instead
data = [ { v : '123' } ]
my code:
let arr = [];
Object.keys(data).map(v => {
console.log(v, data[v]); // here it shows 'user_id' and '123' as it's supposed to
arr.push({ v:data[v] }); // but here it uses the 'v' as property instead of 'user_id'
});
You need to put v inside a square bracket
const data = {
user_id: '123'
}
let arr = [];
Object.keys(data).map(v => {
arr.push({
[v]: data[v]
});
});
console.log(arr)
Alternatively you can also use Object.entries. You dont need initialize let arr = []; as map will create a new array
const data = {
user_id: '123'
}
const arr = Object.entries(data).map(v => {
return {
[v[0]]: v[1]
}
});
console.log(arr)
when you need to use variable as key in object, you must use [].
Example:
const key = 'user_id'
const obj = {
[key]: 'user'
}
## result
{
'user_id': 'user
}
So change v to [v].
let arr = [];
Object.keys(data).map(v => {
arr.push({ [v]:data[v] }); // replace v to [v]
});
** Update: The answer below works great up to the merge. I had to add some iterations into getL2 and getL3 to make all the calls necessary. The issue seemed to be that some of the tasks from L1 did not have a child at L2, and some L2 did not have an L3. So the final results has some empty arrays. the final result before the merge looks like below. right now, the merge function returns the L1 data with no children added.
var result = [
[{
"ID": 1,
"title": "Task 1",
"org": "A"
}, {
"ID": 2,
"title": "Task 2",
"org": "B"
}],
[{}, {},
{
"ID": 10,
"ParentID": 2
}, {
"ID": 11,
"ParentID": 2
}
],
[{}, {}, {
"ID": 20,
"ParentID": 10
}, {
"ID": 21,
"ParentID": 10
}]
]
I continue to struggle with async and promises, despite the amazing help on stack. I tried to reverse engineer some similar posts with no success. I am trying to chain 3 functions that will make multiple REST calls in SharePoint 2013. the first call grabs all items in list taskL1 that match the organization. it uses the ID's to create a set of unique entries. then a second call against taskL2 is made using the the set to find all entries that have those id's in the parentID column. It then creates a set of those IDs to make a final call against taskL3 and matches those IDs to the parentID column in that list. I need to pass all three results along until a final function will merge the data into a nested object.Bascially, put all the L3 tasks under the correct L2 and all the L2 under the correct L1. I can't seem to keep all 3 results passing along until the end and available to a follow on function. https://jsfiddle.net/75ghvms8/
var setL1 = new Set();
var setL2 = new Set();
var taskL1 = [{"id":1,"title":"Task 1","org":"A"},{"id":2,"title":"Task 2","org":"B"},{"id":3,"title":"Task 3","org":"A"}]
var taskL2 = [{"id":20,"parentID":1},{"id":21,"parentID":1},{"id":22,"parentID":2},{"id":23,"parentID":2}]
var taskL3 = [{"id":100,"parentID":20},{"id":111,"parentID":21},{"id":120,"parentID":22},{"id":220,"parentID":23}]
getL1(taskL1,'A').then(()=>{getL2(taskL2,setL1)}).then(()=>{getL3(taskL3,setL2)});
async function getL1(srcList,org){
const l1List = await getData(srcList,org);
console.log(l1List);
return l1List
}
async function getL2(srcList,set){;
const l2List = await getData2(srcList,set);
console.log(l2List);
return l2List
}
async function getL3(srcList,set){
const l3List = await getData3(srcList,set);
console.log(l3List);
return l3List
}
async function getData(srcList,org,result={}) {
const listItems = await getTaskItems(srcList,org);
result = listItems;
return result;
}
async function getData2(srcList,item,result={}) {
let j = 0;
for(let i of item) {
const listItems = await getTaskItems2(srcList,i)
result[j] = listItems;
j++
}
return result
}
async function getData3(srcList,item,result={}) {
let j = 0;
for(let i of item) {
const listItems = await getTaskItems3(srcList,i)
result[j] = listItems;
j++
}
return result
}
function getTaskItems(srcList,org) {
const arrData = srcList.filter(obj=> {
return obj.org === org;
});
for (let i = 0; i < arrData.length; i++) {
setL1.add(arrData[i].id);
}
return {arrData,setL1}
}
function getTaskItems2(srcList,id) {
const arrData = srcList.filter(obj=> {
return obj.parentID === id;
});
for (let i = 0; i < arrData.length; i++) {
setL2.add(arrData[i].id);
}
return {arrData,setL2}
}
function getTaskItems3(srcList,id) {
const arrData = srcList.filter(obj=> {
return obj.parentID === id;
});
return arrData;
}
// real functions are spRest-Lib functions
/*
function getTaskItems(srcList, org) {
return new Promise((resolve,reject) =>{
sprLib.list(srcList).getItems({
listCols: {
columns here
}
})
.then(function(arrData){
for (let i = 0; i < arrData.length; i++) {
setL1.add(arrData[i].ID);
}
resolve(arrData);
})
.catch(function(errMsg) {console.log(errMsg);});
})
}
*/
You'll need to tweak some key names. Promise chaining is achieved by returning custom objects {l1: [], l2: [], l3: []}. Merge can probably be done as you go along each step, but instead here is one way to do it with explicit merge step.
var taskL1 = [{"id":1,"title":"Task 1","org":"A"},{"id":2,"title":"Task 2","org":"B"},{"id":3,"title":"Task 3","org":"A"}]
var taskL2 = [{"id":20,"parentID":1},{"id":21,"parentID":1},{"id":22,"parentID":2},{"id":23,"parentID":2}]
var taskL3 = [{"id":100,"parentID":20},{"id":111,"parentID":21},{"id":120,"parentID":22},{"id":220,"parentID":23}]
async function getL1(org) {
return new Promise((resolve, reject) => {
// assuming some external reqeust
resolve({ l1:
taskL1.filter((item) => item.org === org)
});
})
}
async function getL2(l1Result) {
return new Promise((resolve, reject) => {
const allL1Ids = Array.from(new Set(Object.values(l1Result.map((item) => item.id))));
// assuming some external request
const filteredList = taskL2.filter((item) => allL1Ids.indexOf(item.parentID !== -1));
resolve({ l1: l1Result, l2: filteredList});
})
}
async function getL3(l1Result, l2Result) {
return new Promise((resolve, reject) => {
const allL2Ids = Array.from(new Set(Object.values(l2Result.map((item) => item.id))));
// assuming some external request
const filteredList = taskL3.filter((item) => allL2Ids.indexOf(item.parentID !== -1));
resolve({l1: l1Result, l2: l2Result, l3: filteredList})
})
}
function groupByKey(items, key) {
return items.reduce(function(results, item) {
(results[item[key]] = results[item[key]] || []).push(item);
return results;
}, {});
}
function merge(l1, l2, l3) {
// we want to put l3.parentID into l2.id.children
let l3ByParentId = groupByKey(l3, "parentID");
let l2ById = groupByKey(l2, "id");
Object.keys(l3ByParentId).forEach((parentId) => {
if (l2ById[parentId]) {
l2ById[parentId][0]['l3children'] = l3ByParentId[parentId];
}
});
let l2ByParentId = groupByKey(Object.values(l2ById).map((item) => item[0]), "parentID");
let l1ById = groupByKey(l1, "id");
Object.keys(l2ByParentId).forEach((parentId) => {
if (l1ById[parentId]) {
l1ById[parentId][0]['l2children'] = l2ByParentId[parentId];
}
});
return Object.values(l1ById).map(item => item[0]);
}
getL1("A")
.then((result) => {
return getL2(result.l1)
})
.then((result) => {
return getL3(result.l1, result.l2)
})
.then((result) => {
return merge(result.l1, result.l2, result.l3)
})
.then((result) => {
console.log(JSON.stringify(result, null, 2));
})
I have a problem to make an array of strings into objects of url paths (for breadcrumbs)
I have this array :
const array = ['visit', 'schedule', 'validator']
What I tried :
const routeArray = array.map((b) => ({
label: b,
route: `/${b}`,
}))
console.log(routeArray)
result :
[
{label: "visit", route: "/visit"},
{label: "schedule", route: "/schedule"},
{label: "validator", route: "/validator"},
]
what I want to achieve :
[
{label: "visit", route: "/visit"},
{label: "schedule", route: "/visit/schedule"},
{label: "validator", route: "/visit/schedule/validator"}
]
Any help ?
Just concatenate the String while going through the array:
const array = ['visit', 'schedule', 'validator'];
let route = "";
const result = array.map(label => {
route += '/' + label;
return { label, route };
});
Array.prototype.map(), Array.prototype.slice() and Array.prototype.join() can be your best friends, here:
const input = ['visit', 'schedule', 'validator'];
const output = input.map((item, index) => {
return {
label: item,
route: '/' + input.slice(0, index + 1).join('/')
}
});
// test
console.log(output);
Please check this out and let me know if this is what you were looking for:
const array = ['visit', 'schedule', 'validator']
const newArray = array.map((entry, index) => {
const route = [];
for (let i = 0; i < index + 1; i++) {
route.push(array[i]);
}
return {
label: entry,
route: route.join('/'),
};
});
console.log(newArray);
In this approach, I loop through as many elements as the order of the current element of array, pushing them into the route array. When creating the object properties, I join the elements of route separated by '/'.
Here is how we can do this using the reduce method:
const arr = ["visit", "schedule", "validator"];
const res = arr.reduce((acc, curr, idx, self) => {
// Our route property of our needed data structure
const route = `/${self.slice(0, idx)}${idx > 0 ? "/" + curr : curr}`;
// Our new object
const obj = { label: curr, route };
return [...acc, obj];
}, []);
console.log(res);
Can be done using a for loop. You need to have a variable which tracks your incrementing route and persists over loop iterations.
const array = ['visit', 'schedule', 'validator'];
let ansArray = [];
let incrVal = '';
for(let i = 0 ; i < array.length; i++){
let ans = incrVal + '/' + array[i];
ansArray.push({'label' : array[i], 'route' : ans});
incrVal = ans;
}
console.log(ansArray);
const array = ['visit', 'schedule', 'validator'];
const results = array.map((item, index, arr) => {
return {
label: item,
route: '/' + arr.slice(0, index + 1).join('/'),
};
});
console.log(results);
Using reduce array method
const array = ["visit", "schedule", "validator"];
const res = array.reduce((acc, curr, idx, arr) => {
acc.push({
label: curr,
route:'/'+ arr.slice(0, idx + 1).join('/')
})
return acc;
}, []);
console.log(res);
I think this is the shortest way to do this:
const input = ["visit", "schedule", "validator"];
const res = input.map((label, i, arr) => ({
label,
route: '/' + arr.slice(0, i + 1).join("/")
}));
console.log(input);
console.log(res);
I'm trying to build an object given an array of objects
const someArray = [
{
name: 'x.y',
value: 'Something for Y'
},
{
name: 'x.a.z',
value: 'Something for Z'
}
]
to look like this
{
x: {
a: {
z: 'Something for Z'
},
y: 'Something for Y'
}
}
I have this code
const buildObj = data => {
let obj = {}
data.forEach(item => {
let items = item.name.split('.')
items.reduce((acc, val, idx) => {
acc[val] = (idx === items.length - 1) ? item.value : {}
return acc[val]
}, obj)
})
return obj
}
buildObj(someArray)
but it doesn't include the y keypair. what's missing?
What you want to do is create an object, then for each dotted path, navigate through the object, creating new object properties as you go for missing parts, then assign the value to the inner-most property.
const someArray = [{"name":"x.y","value":"Something for Y"},{"name":"x.a.z","value":"Something for Z"}]
const t1 = performance.now()
const obj = someArray.reduce((o, { name, value }) => {
// create a path array
const path = name.split(".")
// extract the inner-most object property name
const prop = path.pop()
// find or create the inner-most object
const inner = path.reduce((i, segment) => {
// if the segment property doesn't exist or is not an object,
// create it
if (typeof i[segment] !== "object") {
i[segment] = {}
}
return i[segment]
}, o)
// assign the value
inner[prop] = value
return o
}, {})
const t2 = performance.now()
console.info(obj)
console.log(`Operation took ${t2 - t1}ms`)
.as-console-wrapper { max-height: 100% !important; }
This is ABD at this point but I did it with a recursive builder of the path.
const someArray = [
{
name: 'x.y',
value: 'Something for Y'
},
{
name: 'x.a.z',
value: 'Something for Z'
}
]
const createPath = (path, value) => {
if(path.length === 1){
let obj = {}
obj[path.shift()] = value
return obj
}
let key = path.shift();
let outObject = {}
outObject[key] = { ...createPath(path, value) }
return outObject
}
const createObjectBasedOnDotNotation = (arr) => {
let outObject = {}
for(let objKey in arr){
const { name, value } = arr[objKey];
let object = createPath(name.split("."), value)
let mainKey = Object.keys(object)[0];
!outObject[mainKey] ?
outObject[mainKey] = {...object[mainKey]} :
outObject[mainKey] = {
...outObject[mainKey],
...object[mainKey]
}
}
return outObject
}
console.log(createObjectBasedOnDotNotation(someArray))
Here's an option using for loops and checking nesting from the top down.
const someArray = [
{
name: 'x.y',
value: 'Something for Y'
},
{
name: 'x.a.z',
value: 'Something for Z'
}
]
function parseArr(arr) {
const output = {};
for (let i = 0; i < arr.length; i++) {
const {name, value} = arr[i];
const keys = name.split('.');
let parent = output;
for (let j = 0; j < keys.length; j++) {
const key = keys[j];
if (!parent.hasOwnProperty(key)) {
parent[key] = j === keys.length - 1 ? value : {};
}
parent = parent[key];
}
}
return output;
}
console.log(parseArr(someArray));
I want to rewrite an array and to get a new one at the final.
This is my code:
const arr = [
{
type:"Fiat", model:"500", color:"white"
},
{
type:"ford", model:"5300", color:"gray"
}
];
const newArr = arr.map(i => {
const r = {
...arr,
power:2
}
return r
})
console.log(newArr)
Now i get the wrong result, because one every iteration, the new array grow with a copy of the first array:
const r = {
...arr,
power:2
}
How to get the next result?
{
type:"Fiat", model:"500", color:"white", power: 2
},
{
type:"ford", model:"5300", color:"gray", power: 2
}
You are spreading arr .You need to spread i which is the object inside the array.
const arr = [
{
type:"Fiat", model:"500", color:"white"
},
{
type:"ford", model:"5300", color:"gray"
}
];
const newArr = arr.map(i => {
const r = {
...i,
power:2
}
return r;
})
console.log(newArr)
With array function you can implicitly
const arr = [
{
type:"Fiat", model:"500", color:"white"
},
{
type:"ford", model:"5300", color:"gray"
}
];
const newArr = arr.map(i => ({...i, power: 2}));
console.log(newArr)
You need to spread the current object that you are getting as:
const newArr = arr.map(i => ({ ...i, power: 2 }));
You want to do this, you are spreading arr and should be spreading the array getting passed to map (e.g. i):
const newArr = arr.map(i => {
const r = {
...i,
power:2
}
return r
})