Say I have an array of objects like this:
let cars = [
{
"name": "Ford",
"color": ["Blue", "Red"]
},
{
"name": "Toyota",
"color": ["Blue"]
}
]
How can, without using a for loop, flatten the array out (flatMap perhaps?) so my array looks like this:
let cars = [
{
"name": "Ford",
"color": "Blue"
},
{
"name": "Ford",
"color": "Red"
},
{
"name": "Toyota",
"color": "Blue"
}
]
The reason for not wanting to loop through is that my array is large and I have multiple arrays in the object that I wish to "explode" like this (so I end up iterating over the array 5 times).
With .reduce() and .forEach() combination as the following:
const cars = [{ "name": "Ford", "colors": ["Blue", "Red"] }, { "name": "Toyota", "colors": ["Blue"] }];
const result = cars.reduce((a, c) => {
c.colors.forEach(e => {
a.push({ name: c.name, colors: e });
});
return a;
}, []);
console.log(result);
I hope this helps!
You can use flatMap
let cars = [{
"name": "Ford",
"colors": ["Blue", "Red"]
},
{
"name": "Toyota",
"colors": ["Blue"]
}
]
let result = cars.flatMap(e => {
return e.colors.map((color)=>({name:e.name,color}))
});
console.log(result);
For multiple props (just make sure each of them has at least one type and color)
let cars = [
{
"name": "Ford",
"colors": ["Blue", "Red"],
"type": ["4WD", "RWD"]
},
{
"name": "Toyota",
"colors": ["Blue"],
"type":["TYPE"]
}
]
function flatProps(arr,props){
arr = [...arr]; //to perserve the original array
props.forEach(prop => {
arr = arr.flatMap(e => {
return e[prop].map((value) => {
let r = Object.assign({},e);
r[prop] = value;
return r;
})
});
})
return arr;
}
console.log(flatProps(cars,["colors","type"]));
Related
I have an array of objects:
arr1 = [
{
"id": 1,
"color": "blue",
"label": "School",
},
{
"id": 2,
"color": "red",
"label": "Work",
}
]
and a simple array:
arr2 = [ 2, 5 ]
I want to write a method that returns true if one of the object ids from arr1 can be found in arr2. So I could use it with
v-if
later.
What's your suggestion?
let arr1 = [
{
"id": 1,
"color": "blue",
"label": "School",
},
{
"id": 2,
"color": "red",
"label": "Work",
}
]
let arr2 = [ 2, 5 ]
let arr1_id = arr1.map(function (obj) {
return obj.id;
});
function check(array1, array2) {
let intersection = array1.filter(element => array2.includes(element));
if (intersection.length > 0) {
return true
}
else {return false}
}
bool = check(arr1_id,arr2)
console.log(bool)
{
"arr1":[
{
"name":"something1",
"id":"233111f4-9126-490d-a78b-1724009fa484"
},
{
"name":"something2",
"id":"50584c03-ac71-4225-9c6a-d12bcc542951"
},
{
"name":"Unique",
"id":"43cf14ee58ea4d8da43e9a2f208d215c"
},
{
"name":"something4",
"id":"ce0374ba-6d9b-4ff5-98b1-1191d1d2a9a7"
},
{
"name":"something5",
"id":"ef825dc3-003c-4740-955a-bb437cfb4199"
}
],
"arr2":
[
{
"name":"Unique",
"id":"43cf14ee58ea4d8da43e9a2f208d215c"}
]
}
This is list of arrays with keys and values as array, I want to return all the keys based on a particular value;
For Eg:
I want to return the parent keys which are [arr1,arr2], reason being both the arrays contain a value Unique, So I want to return the parent key of both the values, which is arr1 and arr2 respectively.
Note: The list can have n numbers of arrays.
Any help would be appreciated. Thanks in advance.
The simplest way to go about this is:
Loop through the keys in your object
Check if the array contains any objects with the name "Unique"
If so, add the objects key to an array
const obj = {
"arr1": [{ "name": "something1", "id": "233111f4-9126-490d-a78b-1724009fa484" }, { "name": "something2", "id": "50584c03-ac71-4225-9c6a-d12bcc542951" }, { "name": "Unique", "id": "43cf14ee58ea4d8da43e9a2f208d215c" }, { "name": "something4", "id": "ce0374ba-6d9b-4ff5-98b1-1191d1d2a9a7" }, { "name": "something5", "id": "ef825dc3-003c-4740-955a-bb437cfb4199" }],
"arr2": [{ "name": "Unique", "id": "43cf14ee58ea4d8da43e9a2f208d215c" }],
"arr3": [{ "name": "No unique here","id": "Example" }]
}
// Create our array that will contain the keys
const keys = []
// Loop through each key in the object
for (const prop in obj) {
// Use .some to see if any of the objects in this array have the selected name
const containsUnique = obj[prop].some(o => o.name === 'Unique')
if (containsUnique) {
// Add the current key to the array
keys.push(prop)
}
}
// Use the array of keys which contain an object named "Unique"
console.log(keys)
This is a more generic approach:
const getKeysByValue = (data, value) => {
const dataKeys = Object.keys(data);
const valueKey = Object.keys(value);
return dataKeys.filter(currKey => {
for(let element of data[currKey])
if(element[valueKey] === value[valueKey])
return true;
});
}
const data = {
"arr1":[
{
"name":"something1",
"shape": "Trapezium",
"id":"233111f4-9126-490d-a78b-1724009fa484"
},
{
"name":"something2",
"shape": "Octagon",
"id":"50584c03-ac71-4225-9c6a-d12bcc542951"
},
{
"name":"Unique",
"shape": "Square",
"id":"43cf14ee58ea4d8da43e9a2f208d215c"
},
{
"name":"something4",
"shape": "Triangle",
"id":"ce0374ba-6d9b-4ff5-98b1-1191d1d2a9a7"
},
{
"name":"something5",
"shape": "Circle",
"id":"ef825dc3-003c-4740-955a-bb437cfb4199"
}
],
"arr2":
[
{
"name":"Unique",
"shape": "Triangle",
"id":"43cf14ee58ea4d8da43e9a2f208d215c"
}
],
"arr3":
[
{
"name":"Not-Unique",
"shape": "Circle",
"id":"8hcf14ee58ea25g343e9a2f208df215c"
}
]
}
console.log(getKeysByValue(data, {"name": "something2"})); // ["arr1"]
console.log(getKeysByValue(data, {"name": "Unique"})); // ["arr1", "arr2"]
console.log(getKeysByValue(data, {"shape": "Circle"})); // ["arr1", "arr3"]
console.log(getKeysByValue(data, {"shape": "Square"})); // ["arr1"]
The function receives two parameters, data and value. value is expected to be in the format of the value you are looking to filter with. In your example you wanted it to be "Unique" and in each object in the array it was presented like "name": "Unique" so we will send it as an object, {"name": "Unique"}.
In this way you can have different value to filter with. In the example above I added a shape key and value to each element, we can filter by this value too as shown in the example above.
you can do like this :
const obj = {
"arr1": [{ "name": "something1", "id": "233111f4-9126-490d-a78b-1724009fa484" }, { "name": "something2", "id": "50584c03-ac71-4225-9c6a-d12bcc542951" }, { "name": "Unique", "id": "43cf14ee58ea4d8da43e9a2f208d215c" }, { "name": "something4", "id": "ce0374ba-6d9b-4ff5-98b1-1191d1d2a9a7" }, { "name": "something5", "id": "ef825dc3-003c-4740-955a-bb437cfb4199" }],
"arr2": [{ "name": "Unique", "id": "43cf14ee58ea4d8da43e9a2f208d215c" }],
"arr3": [{ "name": "No unique here","id": "Example" }]
}
arr=[]
//loop over dict with pair keys and value
for (const [key, value] of Object.entries(obj)) {
//get the list of name from dict and check it if it contains Unique string
value.map(e=>e.name).includes("Unique") ? arr.push(key) : false
}
console.log(arr)
You can use array some method
const data = {
"arr1": [{
"name": "something1",
"id": "233111f4-9126-490d-a78b-1724009fa484"
},
{
"name": "something2",
"id": "50584c03-ac71-4225-9c6a-d12bcc542951"
},
{
"name": "Unique",
"id": "43cf14ee58ea4d8da43e9a2f208d215c"
},
{
"name": "something4",
"id": "ce0374ba-6d9b-4ff5-98b1-1191d1d2a9a7"
},
{
"name": "something5",
"id": "ef825dc3-003c-4740-955a-bb437cfb4199"
}
],
"arr2": [{
"name": "Unique",
"id": "43cf14ee58ea4d8da43e9a2f208d215c"
}]
}
var obj = [],
keys;
for (keys in data) {
data[keys].some(a => "Unique" === a.name) && obj.push(keys);
}
console.log(obj);
An alternative way that i could think of is using Regexp
var obj = {
"arr1":[
{
"name":"something1",
"id":"233111f4-9126-490d-a78b-1724009fa484"
},
{
"name":"something2",
"id":"50584c03-ac71-4225-9c6a-d12bcc542951"
},
{
"name":"Unique",
"id":"43cf14ee58ea4d8da43e9a2f208d215c"
},
{
"name":"something4",
"id":"ce0374ba-6d9b-4ff5-98b1-1191d1d2a9a7"
},
{
"name":"something5",
"id":"ef825dc3-003c-4740-955a-bb437cfb4199"
}
],
"arr2":
[
{
"name":"Unique",
"id":"43cf14ee58ea4d8da43e9a2f208d215c"}
]
}
let str = JSON.stringify(obj);
let match = str.matchAll(/\"([\w\d]+)\":\[(?:{[\s\S]+},)*{\"name\":\"Unique\"/g);
let parent = [];
for(let m of match){
parent.push(m[1]);
}
This question already has answers here:
How can I group an array of objects by key?
(32 answers)
Closed 1 year ago.
can you help me with this problem with js\react?
I'm trying to manage 2 arrays due to obtain a new object based on their shared attribute (Array A: "id" and Array B: "parent")
I think isn't hard but I'm struggling to do it atm :(
Array A
[{
"id": "606f1a2bebb5fb53804dd3d5",
"name": "cc",
}, {
"id": "606f1a30cfe84430c41dce88",
"name": "bb",
}, {
"id": "606f1a4ed2ff554e4ea11b82",
"name": "ff",
}]
Array B
[{
"id": "3344",
"color": "pink",
"parent": "606f1a2bebb5fb53804dd3d5",
}, {
"id": "3453",
"color": "blue",
"parent": "606f1a30cfe84430c41dce88",
}, {
"id": "3331",
"color": "yellow",
"parent": "606f1a4ed2ff554e4ea11b82",
}, {
"id": "4442",
"color": "black",
"parent": "606f1a30cfe84430c41dce88",
}]
I want merge these two arrays and create a new one where the array B objects are split by "id" of array A.
Something like this:
[{
"606f1a2bebb5fb53804dd3d5": [{
"id": "3344",
"color": "pink",
"parent": "606f1a2bebb5fb53804dd3d5",
}]
}, {
"606f1a30cfe84430c41dce88": [{
"id": "3453",
"color": "blue",
"parent": "606f1a30cfe84430c41dce88",
}, {
"id": "4442",
"color": "black",
"parent": "606f1a30cfe84430c41dce88",
}]
}, {
"606f1a4ed2ff554e4ea11b82": [{
"id": "3331",
"color": "yellow",
"parent": "606f1a4ed2ff554e4ea11b82",
}]
}]
Thanks very much guys
You just need array b for grouping and another object for keeping track of the max key inside of a group.
const
data = [{ id: "3344", color: "pink", parent: "606f1a2bebb5fb53804dd3d5" }, { id: "3453", color: "blue", parent: "606f1a30cfe84430c41dce88" }, { id: "3331", color: "yellow", parent: "606f1a4ed2ff554e4ea11b82" }, { id: "4442", color: "black", parent: "606f1a30cfe84430c41dce88" }],
max = {},
result = data.reduce((r, o) => {
max[o.parent] = (max[o.parent] || 0) + 1;
(r[o.parent] ??= {})[max[o.parent]] = o;
return r;
}, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I think you can loop through the items and then find the parent
let arrayC = [];
arrayB.forEach(item => {
let parent = array1.find(e => e.id === item.parent);
// do something here to combine it into one object
// then arrayC.push(newItem);
});
https://codesandbox.io/s/boring-snowflake-brksj?file=/src/index.js
const result = arrayA.reduce((acc, arrayAItem) => {
return {
...acc,
[arrayAItem.id]: arrayB.filter(
(arrayBItem) => arrayBItem.parent === arrayAItem.id
)
};
}, {});
}]
You can do this with map and filter functions of array.
const newArray = array1.map(array1Item => {
return { [array1Item.id]: array2.filter(array2Item => array2Item.parent === array1Item.id)}
})
Based on the two arrays that you have, I assume that they are only linked by their "parent" ids. If this is the case, you can reduce the B array using the A array as an accumulator.
const a = [
{ "id": "606f1a2bebb5fb53804dd3d5" , "name": "cc" },
{ "id": "606f1a30cfe84430c41dce88" , "name": "bb" },
{ "id": "606f1a4ed2ff554e4ea11b82" , "name": "ff" },
];
const b = [
{ "id": "3344" , "color": "pink" , "parent": "606f1a2bebb5fb53804dd3d5" },
{ "id": "3453" , "color": "blue" , "parent": "606f1a30cfe84430c41dce88" },
{ "id": "3331" , "color": "yellow" , "parent": "606f1a4ed2ff554e4ea11b82" },
{ "id": "4442" , "color": "black" , "parent": "606f1a30cfe84430c41dce88" },
];
const c = Object
.entries(b.reduce((acc, { id, color, parent }) =>
({ ...acc, [parent]: {
...acc[parent],
colors: [...acc[parent].colors, { id, color } ]
}}),
Object.fromEntries(a.map(({ id, name }) =>
[ id, { name, colors: [] } ]))))
.map(([ id, value ]) => value);
console.log(c);
.as-console-wrapper { top: 0; max-height: 100% !important; }
I have arrays like these
arr1 = [{
"_id": 1,
"item": "Pencil",
"color": "Red"
},{
"_id":2,
"item": "Pen",
"color": "Yellow"
},{
"_id": 3,
"item": "Pencil",
"color": "Green"
}]
arr2 = [{
"value":"Pencil",
"price":1000,
},{
"value":"Pen",
"price":1500,
}]
How do I combine this arr2 into arr1 with "value" in arr2 and "price" in arr1 as the key? so that it has the following results
res = [{
"_id": 1,
"item": "Pencil",
"color": "Red",
"price": 1000
},{
"_id":2,
"item": "Pen",
"color": "Yellow",
"price": 1500
},{
"_id": 3,
"item": "Pencil",
"color": "Green",
"price": 1000
}]
You can use map. For example:
let arr3 = arr1.map((el1) => {
let found = arr2.find(el2 => el1.item == el2.value)
if (found)
el1.price = found.price
return el1
})
console.log(arr3)
You can use Map collection to have O(1) while mapping the second array:
const uniquePencils = new Map(arr2.map(s => [s.value, s.price]));
const result = arr1.map(a => ({...a, price: uniquePencils.get(a.item)}));
As mdn says about Map collection:
The Map object holds key-value pairs and remembers the original
insertion order of the keys.
So to create a map collection from array we can use map method:
const uniquePencils = new Map(arr2.map(s => [s.value, s.price]));
Then when we map array, we need to give item name(e.g. Pencil) to Map collection to get object from map collection.
arr1.map(a => ({...a, price: uniquePencils.get(a.item)}));
In addition, we've used ... operator. It is called spread syntax. It copies own enumerable properties from a provided object onto a new object.
An example:
let arr1 = [{
"_id": 1,
"item": "Pencil",
"color": "Red"
},{
"_id":2,
"item": "Pen",
"color": "Yellow"
},{
"_id": 3,
"item": "Pencil",
"color": "Green"
}];
let arr2 = [{
"value":"Pencil",
"price":1000,
},{
"value":"Pen",
"price":1500,
}];
const uniquePencils = new Map(arr2.map(s => [s.value, s.price]));
const result = arr1.map(a => ({...a, price: uniquePencils.get(a.item)}));
console.log(result);
I need to add key value pair at the end of the tree like json object.
[{
"name": "minpur",
"children": [{
"name": "ppp1",
"children": [{
"name": "feeder",
"children": [{
"name": "rmu16",
"children": [{
"name": "invt16",
"children": [{
"aname": "inv 01"
}]
}]
}]
}]
}]
}]
Expected
[{
"name": "minpur",
"children": [{
"name": "ppp1",
"children": [{
"name": "feeder",
"children": [{
"name": "rmu16",
"children": [{
"name": "invt16",
"children": [{
"aname": "inv 01",
**
"value": 300 **
}]
}]
}]
}]
}]
}]
tried recursive function as below
let traverse = function(jsonObj) {
if (jsonObj !== null && typeof jsonObj == "object") {
return Object.entries(jsonObj).forEach(([key, value]) => {
if (key != "aname") {
traverse(value);
} else {
return value;
}
});
}
}
Check if the aname key exists on the object, and add the property if it does. If it doesn't iterate the children with Array.forEach(), and calls traverse on the children.
const traverse = (key, value) => obj => {
const inner = obj => {
if(obj.hasOwnProperty(key)) obj.value = value
else obj.children.forEach(inner)
}
return inner(obj)
}
const tree = [{"name":"minpur","children":[{"name":"ppp1","children":[{"name":"feeder","children":[{"name":"rmu16","children":[{"name":"invt16","children":[{"aname":"inv 01"}]}]}]}]}]}]
tree.forEach(traverse('aname', 300))
console.log(tree)
Here is a more functional solution where the original values are not changed.
The children are inspected and if there is no children, the passed keys are used to extend the current node.
const obj = [{
"name": "minpur",
"children": [{
"name": "ppp1",
"children": [{
"name": "feeder",
"children": [{
"name": "rmu16",
"children": [{
"name": "invt16",
"children": [{
"aname": "inv 01"
}]
}]
}]
}]
}]
}]
function addToLeaf(append, node) {
if (!node.children) {
return {
...node,
...append
}
}
return {
...node,
...{ children: node.children.map(child => addToLeaf(append, child))}
}
}
const result = obj.map((node) => addToLeaf({
value: 300
}, node));
console.log(result);
If you want to use JS utility library lodash it gives you many methods to handle such complex structures.
For this I would suggest _.set - https://lodash.com/docs/4.17.11#set
const _u = _.noConflict();
var object = { 'a': [{ 'b': { 'c': 3 } }] };
_u.set(object, 'a[0].b.c', 4);
console.log(object);
// => 4
_u.set(object, ['x', '0', 'y', 'z'], 5);
console.log(object);
// => 5
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
You can create a recursive function which traverses arrays of objects and merges a found object (by specified key name) with a specified by you argument. No lodash needed:
let data = [{ "name": "minpur", "children": [{ "name": "ppp1", "children": [{ "name": "feeder", "children": [{ "name": "rmu16", "children": [{ "name": "invt16", "children": [{ "aname": "inv 01" }] }] }] }] }] }]
let deepSetByKey = (a, k, setObj) =>
a.forEach(o => k in o ? Object.assign(o, setObj) :
'children' in o ? deepSetByKey(o.children, k, setObj) : 0) && a
deepSetByKey(data, 'aname', { value: 300 }) // call the fn
console.log(data[0].children[0].children[0].children[0].children[0].children[0])
The idea is to recursively traverse with Array.forEach and use Object.assign when you find the prop you are looking for in the current object.