Am looking to map through an array, take the key/value of a specified field, then merge it into the main object.
Currently my array looks like:
const data = [
{
"id": "3QXNO4SDo08FgAfQy3z5",
"title": "Team One",
"scores": [
{
"id": "DbkZljn22YSGVBLxiT4o",
"score": 88
},
{
"id": "v7ss2ypT4qf9RIvIynJp"
"score": 5,
}
]
},
{
"id": "EmoL3dlPWpOPPiLixIYJ",
"title": "Team Two",
"scores": [
{
"id": "DbkZljn22YSGVBLxiT4o",
"score": 77,
},
{
"id": "v7ss2ypT4qf9RIvIynJp",
"score": 0,
}
]
}
]
And I need to simplify it down to:
[
{
"id": "3QXNO4SDo08FgAfQy3z5",
"title": "Team One",
"DbkZljn22YSGVBLxiT4o": 88,
"v7ss2ypT4qf9RIvIynJp": 5,
},
{
"id": "EmoL3dlPWpOPPiLixIYJ",
"title": "Team Two",
"DbkZljn22YSGVBLxiT4o": 77,
"v7ss2ypT4qf9RIvIynJp": 0,
}
]
Taking the unique ID of the score and using it as my object key.
I imagine this requires nested looping to get the result. I would post my coding attempts, but they were seriously flawed and confusing.
You can combine Array#map and Array#reduce to achieve the desired output.
const mapped = data.map(({ scores, ...rest }) => ({
...rest,
...scores.reduce((output, score) => ({ ...output, [score.id]: score.score }), {})
}));
your questiopn is not clear ..
but this answer may help you
const data= [
{
"id": "3QXNO4SDo08FgAfQy3z5",
"title": "Team One",
"scores": [
{
"id": "DbkZljn22YSGVBLxiT4o",
"score": 88
},
{
"id": "v7ss2ypT4qf9RIvIynJp"
"score": 5,
}
]
},
{
"id": "EmoL3dlPWpOPPiLixIYJ",
"title": "Team Two",
"scores": [
{
"id": "DbkZljn22YSGVBLxiT4o",
"score": 77,
},
{
"id": "v7ss2ypT4qf9RIvIynJp",
"score": 0,
}
]
}
]
by click on data field:
const array = [];
function handleSelect(id) {
const copyData = [...data];
const foundItems = copyData.map(item => item.id === id);
array.push(foundItems)
}
finally array is:
const array = [
{
"id": "3QXNO4SDo08FgAfQy3z5",
"title": "Team One",
"DbkZljn22YSGVBLxiT4o": 88,
"v7ss2ypT4qf9RIvIynJp": 5,
},
{
"id": "EmoL3dlPWpOPPiLixIYJ",
"title": "Team Two",
"DbkZljn22YSGVBLxiT4o": 77,
"v7ss2ypT4qf9RIvIynJp": 0,
}
]
const flattenedArray = data.map((dt) => {
let ar = [];
dt.scores.forEach((n, i) => (ar = { ...ar, [n.id]: n.score }));
return { ...dt, ...ar };
});
Returns the desired flattened array.
Related
Here i have skills array and employees array and i am trying to get the employees that includes all the skills that are included in skills array using reduce, filter or find method. I am trying to stored the filtered employees in filteredItems but got stuck in it.
filteredItems = Skills?.length>0 ?
Employees?.filter((item) => {
return item.Skills.find((ele) => {
return Skills.find((el) => {
if(el.value === ele.id){
return ele
}
})
})
}) : []
Below are the arrays mentioned.
Skills Array
[
{
"value": 6,
"label": "Marketing"
},
{
"value": 20,
"label": "Golang"
}
]
Employees Array
[
{
"name": "Hassan",
"id": 56,
"Skills": [
{
"id": 20,
"name": "Golang",
},
],
},
{
"name": "Haroon",
"id": 95,
"Skills": [
{
"id": 6,
"name": "Marketing",
},
{
"id": 20,
"name": "Golang",
},
],
},
]
For example, in above scenario of arrays it should return employee of id of 95 not return employee of id 56 because it includes skills but not all that are mention in skills array.
I found it easier to first encapsulate an array of skill IDs to search for.
let skillIds = Skills.map(s => s.value);
Then I filtered and compared the end result to the length of the skill Ids array:
let filteredItems = Skills?.length > 0 ?
Employees?.filter(item => item.Skills.filter( s =>
skillIds.includes(s.id)).length==skillIds.length): []
let Skills = [{
"value": 6,
"label": "Marketing"
}, {
"value": 20,
"label": "Golang"
}]
let Employees = [{
"name": "Hassan",
"id": 56,
"Skills": [{
"id": 20,
"name": "Golang",
}],
}, {
"name": "Haroon",
"id": 95,
"Skills": [{
"id": 6,
"name": "Marketing",
},
{
"id": 20,
"name": "Golang",
},
],
}, ]
let skillIds = Skills.map(s => s.value);
let filteredItems = Skills?.length > 0 ?
Employees?.filter(item => item.Skills.filter( s => skillIds.includes(s.id)).length==skillIds.length): []
console.log(filteredItems)
You could create another property in the employees array.. call it "QUalified". Default it to true, then set it to false when the employee doesn't have a skill in the skills array.
let arSkills = [
{
"value": 6,
"label": "Marketing"
},
{
"value": 20,
"label": "Golang"
}
];
let arEmp = [
{
"name": "Hassan",
"id": 56,
"Skills": [
{
"id": 20,
"name": "Golang",
},
],
},
{
"name": "Haroon",
"id": 95,
"Skills": [
{
"id": 6,
"name": "Marketing",
},
{
"id": 20,
"name": "Golang",
},
],
},
];
arEmp.forEach(ele =>{
ele.Qualified = true;
let arTmp = [];
for(let {id} of ele.Skills)
arTmp.push(id)
for(let {value} of arSkills)
if(!arTmp.includes(value))
ele.Qualified = false
});
let arQual = arEmp.filter((ele) =>{
return ele.Qualified
});
console.log(arQual);
I am trying to find a match in a object of arrays and clone this, change the ID and insert this after the found match.
Each plan has clusters and each cluster has goals, the idea is that I need to clone a goal and insert this AFTER the cloned goal (it will be loaded below this goal in the UI).
Main structure
{
"id": 100,
"title": "Plan ABC",
"clusters": [
{
"id": 1,
"subject": "Some subject",
"goals": [
{
"id": 1,
"title": "Goal A",
},
{
"id": 2,
"title": "Goal B",
},
{
"id": 3,
"title": "Goal C",
},
],
},
{
"id": 2,
"subject": "Some subject",
"goals": [
{
"id": 4,
"title": "Goal D",
},
{
"id": 5,
"title": "Goal E",
},
{
"id": 6,
"title": "Goal F",
},
],
},
]
}
My test code
// this would not work ofcourse!
const newId = 12345;
const matchToId = 2;
plan.clusters?.map(cluster => {
cluster?.goals?.map((goal, i) => {
if (goal.id === matchToId) {
// will copy goal with id 2
const copyGoal = goal;
return {...goal, ...copyGoal};
}
return {...goal};
});
// this will work but it will change the id but not copy and add a the new object
plan.clusters = clusters.map(cluster => {
return {
...cluster,
goals: cluster.goals?.filter(goal => {
if (itemId == goal.id) {
const cloned = goal;
cloned.id = 12345;
return {...goal, cloned};
}
return goal;
}),
};
});
What I want
{
"id": 100,
"title": "Plan ABC",
"clusters": [
{
"id": 1,
"subject": "Some subject",
"goals": [
{
"id": 1,
"title": "Goal A",
},
{
"id": 2,
"title": "Goal B",
},
// this will be added
{
"id": 12345,
"title": "COPIED GOAL",
},
// ---
{
"id": 3,
"title": "Goal C",
},
],
},
{
"id": 2,
"subject": "Some subject",
"goals": [
{
"id": 4,
"title": "Goal D",
},
{
"id": 5,
"title": "Goal E",
},
{
"id": 6,
"title": "Goal F",
},
],
},
]
}
This may be one possible solution to achieve the desired objective.
Code Snippet
// check if "tgtId" is present in "goals" array (parameter: "arr")
// and if so, insert "newObj" (parameter: "obj") into the array
const copyObjToGoal = (arr, tgtId, obj) => {
let resObj = {goals: arr}; // the default "result object"
const tgtIdx = arr.findIndex( // search for "tgtId"
({ id }) => id === tgtId
);
if (~tgtIdx) { // if tgtIdx is not -1 (ie, tgtId was found in arr)
const newArr = [ // non-shallow-copy of "arr" (to prevent mutation)
...arr.map(
x => ({...x})
)
]; // mutate the copied "newArr", not the parameter "arr"
newArr.splice(
tgtIdx + 1, // add "after" the "tgtId" position in "goals" array
0, // 0 indicates not to remove any element
{...obj} // destructure to shallow-copy the "newObj" object
);
resObj = { // update the resObj by re-assigning
goals: [...newArr]
};
};
return resObj; // return the result-object
};
// search and insert new/copied goal (not mutating 'myObj')
const searchAndInsert = (tgtId, newObj, obj) => (
Object.fromEntries( // transform below result back into object
Object.entries(obj) // iterate key-value pairs of "obj"
.map(([k, v]) => {
if (k !== 'clusters') { // if key is not "clusters", no change
return [k, v];
} else { // else (for "clusters"
return [ // transform the "goals" array for each cluster
k, // where "tgtId" is found
v.map( // iterate over array of "clusters"
({goals, ...r1}, idx) => {
return { // return each "clusters" array object
...r1,
...copyObjToGoal(goals, tgtId, newObj)
}
}
)
];
}
})
)
);
const myObj = {
"id": 100,
"title": "Plan ABC",
"clusters": [
{
"id": 1,
"subject": "Some subject",
"goals": [
{
"id": 1,
"title": "Goal A",
},
{
"id": 2,
"title": "Goal B",
},
{
"id": 3,
"title": "Goal C",
}
]
},
{
"id": 2,
"subject": "Some subject",
"goals": [
{
"id": 4,
"title": "Goal D",
},
{
"id": 5,
"title": "Goal E",
},
{
"id": 6,
"title": "Goal F",
}
]
}
]
};
const targetGoalId = 2;
const newGoalObj = { id: '12345', title: 'copied goal' };
console.log(
'Test case 1, from question\n',
searchAndInsert(targetGoalId, newGoalObj, myObj)
);
console.log(
'Test case 2, bespoke\n',
searchAndInsert(6, { id: '12345', title: 'copied again' }, myObj)
);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Explanation
Inline comments in the above snippet describe the significant aspects of the solution.
Notes
This solution employs below JavaScript features:
Array .findIndex()
... spread
Array .splice()
Array .map()
Object.fromEntries()
Object.entries()
De-structuring
I need to get the parent id of the specific child.
Here is my sample JSON, If I give entity id 32 it should return 6 as parent Id and if I give 30 it should return 5 as parent id.
const arr = [{
"id": 0,
"name": "My Entity",
"children": [
{
"id": 1,
"name": "MARKET",
"children": [
{
"id": 2,
"name": "Sales",
"children": [
{
"id": 3,
"name": "District 1",
"children": [
{
"id": 5,
"name": "Area 1",
"children": [
{
"entityId": 30,
"id": 26,
"name": "Mumbai"
},
{
"entityId": 31,
"id": 26,
"name": "Hyderabad"
}
],
"num": 0,
},
{
"id": 6,
"name": "Area 2",
"children": [
{
"entityId": 32,
"id": 32,
"name": "Karnataka"
},
{
"entityId": 33,
"id": 33,
"name": "Andhra Pradesh"
}
],
"num": 0,
},
]
},
]
},
]
},
]
}]
Here is the code I have tried
const findParent = (arr, entityId) => {
for (let i = 0; i < arr.length; i++) {
if (arr[i].entityId === entityId) {
return [];
} else if (arr[i].children && arr[i].children.length) {
const t = findParents(arr[i].children, entityId);
if (t !== false) {
t.push(arr[i].id);
return t;
}
}
}
return false;
};
findParents(arr, 30);
But it is returning like below
[
5,
3,
2,
1,
0
]
But I want the output to be
[
5
]
Kindly help me on this, thanks
Replace this:
t.push(arr[i].id);
with:
if (t.length == 0) t.push(arr[i].id);
I would suggest easier solution
const findParent = (arr, entityId) => {
const children = arr.flatMap(parent =>
(item.children || []).map(child => ({ parent, child, entityId: child.entityId }))
)
const res = children.find(item => item.entityId === entityId)
return res.entityId || findChildren(res.map(v => v.child), entityId)
}
For example: I have an array of objects like this:
let arrayOfObjects: [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
];
Now I want to replace or overwrite the array above with the same array, but including different values (same keys, different values):
let arrayOfObjects: [
{ "id": 0, "name": "Not Available" },
{ "id": 1, "name": "Not Ready" },
{ "id": 2, "name": "Not Started" }
];
How can this be done in TypeScript?
Try this JS
let oneArray = [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
];
let twoArray = [
{ "id": 0, "name": "Not Available" },
{ "id": 1, "name": "Not Ready" },
{ "id": 2, "name": "Not Started" }
];
let newArray = Object.assign([], oneArray, twoArray);
console.log(newArray);
In TS
interface Data {
oneArray: array;
twoArray: array;
}
function merge(data: Data) {
return Object.assign([], data.oneArray, data.twoArray);
}
let user = {
oneArray: [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
],
twoArray: [
{ "id": 0, "name": "Not Available" },
{ "id": 1, "name": "Not Ready" },
{ "id": 2, "name": "Not Started" }
]
};
console.log(merge(user));
Sure :)
let arrayOfObjects = [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
];
const newValues = ['Not Available', 'Not Ready', 'Not Started'];
newValues.forEach((value, i) => {
arrayOfObjects.find(o => o.id === i).name = value;
});
console.log(arrayOfObjects);
I wouldn't recommend this though: functional programming is awesome.
let arrayOfObjects = [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
];
let names = ['Not Available', 'Not Ready', 'Not Started']
let result = arrayOfObjects.map((user, index) => ({ ...user, name: names[index] }))
console.log(result)
I have the following data that is an array of nested objects:
"categories": [
{
"id": 1,
"name": "Category 1",
"years": [
{ "id": 1, "name": "1" },
{ "id": 2, "name": "2" }
]
},
{
"id": 2,
"name": "Category 2",
"years": [
{ "id": 2, "name": "2" },
{ "id": 3, "name": "3" }
]
}
]
I want to extract unique years in a separate array (desired output):
[
{ "id": 1, "name": "1" },
{ "id": 2, "name": "2" },
{ "id": 3, "name": "3" },
]
When I map out the years, I'm getting an array of arrays, how should I extract the unique objects for years?
let years = categories.map( (c) => { return c.years })
You can use a Map to filter duplicate years from the array of values using id as the key, and reduce() on both categories and years using the map as the accumulator:
const categories = [{
"id": 1,
"name": "Category 1",
"years": [
{ "id": 1, "name": "1" },
{ "id": 2, "name": "2" }
]
},
{
"id": 2,
"name": "Category 2",
"years": [
{ "id": 2, "name": "2" },
{ "id": 3, "name": "3" }
]
}
];
const years = categories.reduce(
(map, category) => category.years.reduce(
(map, year) => map.set(year.id, year),
map
),
new Map()
);
console.log([...years.values()]);
You can use reduce and Map
let data = [{"id": 1,"name": "Category 1","years": [{ "id": 1, "name": "1" },{ "id": 2, "name": "2" }]},{"id": 2,"name": "Category 2","years": [{ "id": 2, "name": "2" },{ "id": 3, "name": "3" }]}]
let final = data.reduce((op,{years}) => {
years.forEach(({id, name}) => {
let key = id + '-' + name
op.set(key, op.get(key) || {id, name})
})
return op
},new Map())
console.log([...final.values()])