How to get an object's value from another object's key? - javascript

Having:
const colors = [
{id: 1, name: "blue"},
{id: 2, name: "red"},
{id: 3, name: "green"}
];
And:
const shirts = [
{id: 1, color: 2},
{id: 2, color: 3},
{id: 3, color: 2},
{id: 4, color: 1},
{id: 5, color: 3}
];
How can I reference the colors in shirts by the id in colors? I need to end up with shirt.color = blue.
I'm thinking about something like this, but can't get it right:
if (shirt.color === color.id) {
shirt.color = color.name;
}
Thanks in advance!

You can use forEach
const colors = [
{id: 1, name: "blue"},
{id: 2, name: "red"},
{id: 3, name: "green"}
];
const shirts = [
{id: 1, color: 2},
{id: 2, color: 3},
{id: 3, color: 2},
{id: 4, color: 1},
{id: 5, color: 3}
];
shirts.forEach(e=>{
colors.forEach(c=>{
if(e.color == c.id ){
e.color = c.name;
}
})
})
console.log(shirts);

You can use Array.map() for that to loop over the colors and then use Array.filter() to get all the shirts that matches color.id === shirt.color. With that you can then assign that color name to all the shirt object as expected.
const colors = [
{id: 1, name: "blue"},
{id: 2, name: "red"},
{id: 3, name: "green"}
];
const shirts = [
{id: 1, color: 2},
{id: 2, color: 3},
{id: 3, color: 2},
{id: 4, color: 1},
{id: 5, color: 3}
];
colors.map((color) => {
let matchShirt = shirts.filter((shirt) => color.id === shirt.color);
matchShirt.forEach((shirt) => shirt.color = color.name);
});
console.log(shirts);

You could take a Map and create new objects with the color name.
const
colors = [{ id: 1, name: "blue" }, { id: 2, name: "red" }, { id: 3, name: "green" }],
shirts = [{ id: 1, color: 2 }, { id: 2, color: 3 }, { id: 3, color: 2 }, { id: 4, color: 1 }, { id: 5, color: 3 }],
colorMap = new Map(colors.map(({ id, name }) => [id, name])),
result = shirts.map(o => ({ ...o, name: colorMap.get(o.color) }));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

const colors = [
{id: 1, name: "blue"},
{id: 2, name: "red"},
{id: 3, name: "green"}
];
const shirts = [
{id: 1, color: 2},
{id: 2, color: 3},
{id: 3, color: 2},
{id: 4, color: 1},
{id: 5, color: 3}
];
shirts.forEach(s => {
s.color = (colors.find(c => c.id === s.color) || {}).name;
});
console.log(shirts);

If you use an object for the color codes, it makes your life so much easier. It avoids having to loop over it and convert it into a format that resembles this for a quick look up.
const colors = {
1: "blue",
2: "red",
3: "green"
}
const shirts = [
{id: 1, color: 2},
{id: 2, color: 3},
{id: 3, color: 2},
{id: 4, color: 1},
{id: 5, color: 3}
];
shirts.forEach( shirt => shirt.colorName = colors[shirt.color] )
console.log(shirts)
If it really has to be in that format, than do the conversion
const colors = [
{id: 1, name: "blue"},
{id: 2, name: "red"},
{id: 3, name: "green"}
];
const shirts = [
{id: 1, color: 2},
{id: 2, color: 3},
{id: 3, color: 2},
{id: 4, color: 1},
{id: 5, color: 3}
];
const colorCodes = colors.reduce((o, c) => { o[c.id] = c.name; return o }, {})
shirts.forEach( shirt => shirt.colorName = colorCodes[shirt.color] )
console.log(shirts)

Given
const colors = [
{id: 1, name: "blue"},
{id: 2, name: "red"},
{id: 3, name: "green"}
];
The shape of colors above is an array of objects with names and ids. This makes the code needlessly awkward.
We can dramatically simplify things by making colors an object.
const colors = {
1: "blue",
2: "red",
3: "green"
};
const shirts = [
{id: 1, color: 2},
{id: 2, color: 3},
{id: 3, color: 2},
{id: 4, color: 1},
{id: 5, color: 3}
];
function assignShirtColor(shirt) {
shirt.color = colors[shirt.color];
}
Then all we need to do is write
shirts.forEach(assignShirtColor);

Related

Create a hierarchy of arrays from a flat array

Consider I have an array like this
const ar = [
{id: 1, name: "A", parent: null},
{id: 2, name: "B", parent: 1},
{id: 11, name: "AA", parent: 1},
{id: 12, name: "AB", parent: 1},
{id: 111, name: "AAA", parent: 11},
{id: 41, name: "CC", parent: 4},
{id: 4, name: "C", parent: 1},
];
How do I create a hierarchy of just one object like this
{
id: 1,
name: "A",
parent: null,
children: [
{
id: 11,
name: "AA",
parent: 1,
children: [
{id: 111, name: "AAA", parent: 11}],
},
{id: 2, name: "B", parent: 1, children: []},
{
id: 4,
name: "C",
parent: 1,
children: [{id: 41, name: "CC", parent: 4, children: []}],
},
],
}
The id is actually not a number in my actual app. It's a random string BTW.
I could do it recursively by drilling through the children array but it is not the most effective way. Can somebody help please?
const ar = [
{id: 1, name: "A", parent: null},
{id: 2, name: "B", parent: 1},
{id: 11, name: "AA", parent: 1},
{id: 12, name: "AB", parent: 1},
{id: 111, name: "AAA", parent: 11},
{id: 41, name: "CC", parent: 4},
{id: 4, name: "C", parent: 1},
];
const hierarchy = (arr) => {
const map = {};
let root;
for (const ele of arr) {
map[ele.id] = ele;
ele.children = [];
}
for (const ele of arr) {
if (map[ele.parent] != undefined)
map[ele.parent].children.push(ele);
else
root = ele;
}
return root;
}
console.log(hierarchy(ar));
First step is to map the items by the id so you have an easy look up so you are not looping over the array multiple times. After that you just need to loop over and add a children array to the parent and add the reference.
const ar = [
{id: 1, name: "A", parent: null},
{id: 2, name: "B", parent: 1},
{id: 11, name: "AA", parent: 1},
{id: 12, name: "AB", parent: 1},
{id: 111, name: "AAA", parent: 11},
{id: 41, name: "CC", parent: 4},
{id: 4, name: "C", parent: 1},
];
// make a look up by the id
const mapped = ar.reduce((acc, item) => {
acc[item.id] = item;
return acc;
}, {});
// loop over
const result = ar.reduce((acc, item) => {
// if there there is no parent, we know it is the first so return it
const parentId = item.parent;
if (!parentId) return item;
// if we have a parent, see if we found this yet, if not add the array
mapped[parentId].children = mapped[parentId].children || [];
// set the item as a child
mapped[parentId].children.push(item);
return acc;
}, null);
console.log(result)
You can iterate through the array and push the elem to the right place each time.
To get the root, you can then retrieve the element without parent.
const arr = [{id: 1, name: "A", parent: null},
{id: 2, name: "B", parent: 1},
{id: 11, name: "AA", parent: 1},
{id: 12, name: "AB", parent: 1},
{id: 111, name: "AAA", parent: 11},
{id: 41, name: "CC", parent: 4},
{id: 4, name: "C", parent: 1}]
arr.forEach(elem => elem.children = [])
arr.forEach(elem => {
if(elem.parent){
const parent = arr.find(x => x.id === elem.parent)
if(parent)parent.children.push(elem)
}
})
console.log(arr.find(x => !x.parent))
Note : If you want to optimize a little more, you can add the children array in the second forEach

How to find matching colors in an array of objects?

I have this list of colors:
colors = ['red', 'yellow', 'white'];
This is my array objects:
products = [
{id: 1, ​name: "Apple", color: ['Brown','black'] },
{id: 2, name: "Orange", color: ['red']},
​{id: 3, name: "Grape", color: ['red','white']},
​ {id: 4, name: "Banana", color: ['yellow']},
{id: 5, name: "Mandarin", color: ['blue']}
];
I want to return an array of the matching colors like so: [Orange,Grape,Banana];
Try this, it traverses through product lists and checks if the color list contains one of the colors
const list = products.filter((obj)=>{
return obj.color.some(c=>colors.includes(c))
});
Try using a filter and a map...
const colors = ['red', 'yellow', 'white'];
const products = [
{id: 1, name: "Apple", color: ['Brown','black'] },
{id: 2, name: "Orange", color: ['red']},
{id: 3, name: "Grape", color: ['red','white']},
{id: 4, name: "Banana", color: ['yellow']},
{id: 5, name: "Mandarin", color: ['blue']}
];
const arr = products.filter(product => {
return product.color.some(color => colors.some(c => c === color))
}).map(product => product.name);
console.log(arr);
This should be what you're looking for as it produces the correct list of items as requested in the question.
This runs 2 filters to find matching colors
products.filter(e => e.color.filter( c=> colors.includes(c)).length>0)
colors = ['red', 'yellow', 'white']
products = [
{id: 1, name: "Apple", color: ['Brown','black'] },
{id: 2, name: "Orange", color: ['red']},
{id: 3, name: "Grape", color: ['red','white']},
{id: 4, name: "Banana", color: ['yellow']},
{id: 5, name: "Mandarin", color: ['blue']}
]
let filtered = products.filter(e => e.color.filter( c=> colors.includes(c)).length>0)
console.log(filtered)
let requiredArray = products.filter(({ color }) => colors.some(item => color.includes(item)));
console.log(requiredArray);

In JavaScirpt, how do I filter the elements of the same field in two arrays and return a new two-dimensional array

This is an example:
I want to regroup arry2 according to the fields in arry1
var arry1 = [
{id: 1, parentId: 0, name: "phone"},
{id: 2, parentId: 1, name: "nick"}
];
var arry2 = [
{id: 7, parentId: 0, name: "phone_item1"},
{id: 8, parentId: 1, name: "phone_item2"},
{id: 9, parentId: 0, name: "nick_item1"},
{id: 10, parentId: 1, name: "nick_item2"}
];
let newArrys = arry1.filter((item)=>{
return leve_two.indexOf(arry2.parentId) == -1
})
I want to return a two-dimensional array:
[[
{id: 7, parentId: 0, name: "phone_item1"},
{id: 9, parentId: 0, name: "nick_item1"}
],[
{id: 8, parentId: 1, name: "phone_item2"},
{id: 10, parentId: 1, name: "nick_item2"}
]]
I tried Array.filter and so on.
Can you help me?
You can use filter() method along-with Object.values() to get the desired output:
const arr1 = [
{id: 1, parentId: 0, name: "phone", level: 0, productCount: 0},
{id: 2, parentId: 1, name: "nick", level: 0, productCount: 0}
];
const arr2 = [
{id: 7, parentId: 0, name: "phone_item1", level: 1, productCount: 0},
{id: 8, parentId: 1, name: "phone_item2", level: 1, productCount: 0},
{id: 9, parentId: 0, name: "nick_item1", level: 1, productCount: 0},
{id: 10, parentId: 1, name: "nick_item2", level: 1, productCount: 0}
];
const filterIds = arr1.map(({ parentId }) => parentId);
const arr3 = Object.values(arr2.reduce((r, c) => {
r[c.parentId] = r[c.parentId] || [];
r[c.parentId].push(c);
return r;
}, {}));
console.log(arr3);
.as-console-wrapper { max-height: 100% !important; top: 0; }
It looks just like grouping arry2 by parentId and arry1 looks useless 🤔
Use some lib for this. For example Ramda way:
const result = R.pipe(
R.groupBy(R.prop("parentId")),
R.toPairs,
R.map(R.last)
)(arry2)

How can I convert normal array of objects to multilevel array in javascript? [duplicate]

This question already has answers here:
Build tree array from flat array in javascript
(34 answers)
Closed 4 years ago.
My normal array object like this :
var b = [
{id: 1, name: 'England',parent_id: null},
{id: 2, name: 'Spain',parent_id: null},
{id: 3, name: 'Chelsea',parent_id: 1},
{id: 4, name: 'Manchester United',parent_id: 1},
{id: 5, name: 'Real Madrid',parent_id: 2},
{id: 6, name: 'Barcelona',parent_id: 2},
{id: 7, name: 'Hazard',parent_id: 3},
{id: 8, name: 'Morata',parent_id: 3},
{id: 9, name: 'Pogba',parent_id: 4},
{id: 10, name: 'Lukaku',parent_id: 4},
{id: 11, name: 'Ronaldo',parent_id: 5},
{id: 12, name: 'Bale',parent_id: 5},
{id: 13, name: 'Messi',parent_id: 6},
{id: 14, name: 'Suarez',parent_id: 6},
];
I want to convert the object array to be like this :
var b = [
{
name: 'England',
children: [
{
name: 'Chelsea',
children: [
{name: 'Hazard'},
{name: 'Morata'}
]
},
{
name: 'Manchester United',
children: [
{name: 'Pogba'},
{name: 'Lukaku'}
]
}
]
},
{
name: 'Spain',
children: [
{
name: 'Real Madrid',
children: [
{name: 'Ronaldo'},
{name: 'Bale'}
]
},
{
name: 'Barcelona',
children: [
{name: 'Messi'},
{name: 'Suarez'}
]
},
]
}
];
It seems it will be separated using key parent_id
But i'm still confused to implement it
How can I convert the array object like that?
Please help me guys
.filter() the b so it contains only items with parent_id: null
.map() remaining items, assigning children to them
.map() children for each of the root level parents to return them without parent_id field (optional, not in the example)
var b = [
{id: 1, name: 'England',parent_id: null},
{id: 2, name: 'Spain',parent_id: null},
{id: 3, name: 'Chelsea',parent_id: 1},
{id: 4, name: 'Manchester United',parent_id: 1},
{id: 5, name: 'Real Madrid',parent_id: 2},
{id: 6, name: 'Barcelona',parent_id: 2},
{id: 7, name: 'Hazard',parent_id: 3},
{id: 8, name: 'Morata',parent_id: 3},
{id: 9, name: 'Pogba',parent_id: 4},
{id: 10, name: 'Lukaku',parent_id: 4},
{id: 11, name: 'Ronaldo',parent_id: 5},
{id: 12, name: 'Bale',parent_id: 5},
{id: 13, name: 'Messi',parent_id: 6},
{id: 14, name: 'Suarez',parent_id: 6},
];
const done = b.filter(person => !person.parent_id).map(person => {
return {
id : person.id,
name : person.name,
children: b.filter(child => child.parent_id == person.id)
}
});
console.log(done);

How to sum the same objects in array

It is possible to sum the values of an array if they are the same like this:
var COLLECTION = [
{
"coords":[1335,2525],
"items":[
{id: "boletus",qty: 1},
{id: "lepiota",qty: 3},
{id: "boletus",qty: 2},
{id: "lepiota",qty: 4},
{id: "carbonite",qty: 4},
],
},
{
"coords":[1532,2889],
"items":[
{id: "boletus",qty: 2},
{id: "lepiota",qty: 6},
{id: "boletus",qty: 1},
{id: "lepiota",qty: 4},
{id: "chamomile",qty: 4},
],
}]
To return something like this:
var COLLECTION = [
{
"coords":[1335,2525],
"items":[
{id: "boletus",qty: 3},
{id: "lepiota",qty: 7},
{id: "carbonite",qty: 4},
],
},
{
"coords":[1532,2889],
"items":[
{id: "boletus",qty: 3},
{id: "lepiota",qty: 10},
{id: "chamomile",qty: 4},
],
}]
Wihout losing the other parts of the array?
(doing by hand is hard because I have more than 10 thousand duplicates like the example above, and the array have 600 thousand entries.
You could use map() to create new array and inside reduce() to group items objects by id and sum qty.
var data = [{"coords":[1335,2525],"items":[{"id":"boletus","qty":1},{"id":"lepiota","qty":3},{"id":"boletus","qty":2},{"id":"lepiota","qty":4},{"id":"carbonite","qty":4}]},{"coords":[1532,2889],"items":[{"id":"boletus","qty":2},{"id":"lepiota","qty":6},{"id":"boletus","qty":1},{"id":"lepiota","qty":4},{"id":"chamomile","qty":4}]}]
const result = data.map(function({coords, items}) {
return {coords, items: Object.values(items.reduce(function(r, e) {
if(!r[e.id]) r[e.id] = Object.assign({}, e)
else r[e.id].qty += e.qty
return r;
}, {}))}
})
console.log(result)
You could take the power of Map and render the result by using Array.from with a mapping function which builds new objects for items.
var COLLECTION = [{ coords: [1335, 2525], items: [{ id: "boletus", qty: 1 }, { id: "lepiota", qty: 3 }, { id: "boletus", qty: 2 }, { id: "lepiota", qty: 4 }, { id: "carbonite", qty: 4 }], }, { coords: [1532, 2889], items: [{ id: "boletus", qty: 2 }, { id: "lepiota", qty: 6 }, { id: "boletus", qty: 1 }, { id: "lepiota", qty: 4 }, { id: "chamomile", qty: 4 }] }];
COLLECTION.forEach(o => {
var map = new Map;
o.items.forEach(({ id, qty }) => map.set(id, (map.get(id) || 0) + qty));
o.items = Array.from(map, ([id, qty]) => ({ id, qty }));
});
console.log(COLLECTION);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use the functions forEach and reduce
This approach mutates the original array
var COLLECTION = [ { "coords":[1335,2525], "items":[ {id: "boletus",qty: 1}, {id: "lepiota",qty: 3}, {id: "boletus",qty: 2}, {id: "lepiota",qty: 4}, {id: "carbonite",qty: 4}, ], }, { "coords":[1532,2889], "items":[ {id: "boletus",qty: 2}, {id: "lepiota",qty: 6}, {id: "boletus",qty: 1}, {id: "lepiota",qty: 4}, {id: "chamomile",qty: 4}, ], }];
COLLECTION.forEach((o) => {
o.items = Object.values(o.items.reduce((a, c) => {
(a[c.id] || (a[c.id] = {id: c.id, qty: 0})).qty += c.qty;
return a;
}, {}));
});
console.log(COLLECTION);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If you want to create a new array and keep the original data:
This approach uses the function map to create a new "cloned" array.
var COLLECTION = [ { "coords":[1335,2525], "items":[ {id: "boletus",qty: 1}, {id: "lepiota",qty: 3}, {id: "boletus",qty: 2}, {id: "lepiota",qty: 4}, {id: "carbonite",qty: 4}, ], }, { "coords":[1532,2889], "items":[ {id: "boletus",qty: 2}, {id: "lepiota",qty: 6}, {id: "boletus",qty: 1}, {id: "lepiota",qty: 4}, {id: "chamomile",qty: 4}, ] }],
result = COLLECTION.map(o => o);
result.forEach((o) => {
o.items = Object.values(o.items.reduce((a, c) => {
(a[c.id] || (a[c.id] = {id: c.id, qty: 0})).qty += c.qty;
return a;
}, {}));
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories