Javascript - join arrays of objects - javascript

I have method in a class that returns 8 arrays with 8 objects each:
[{...},{...},{...},{...},{...},{...},{...},{...}] [{...},{...},{...},{...},{...},{...},{...},{...}] etc.
the result I would like to get is one array containing all these objects, like this:
[{...},{...},{...},{...},{...},{...},{...},{...},{...},{...},{...},{...}] etc.
what function should I use to get this?
I tried with concat() but here I have to pass another array as a parameter...

You can use
arr.flat(depth);
This example is given in the mozilla javascript documentation:
var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]
var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]

Seems to be that .flat() is exactly what you need.

If you are simply trying to merge all the objects into a single array, one way to do this would be to use Array.reduce.
const result = [
[{}],
[{}],
[{}],
[{}],
[{}],
[{}],
[{}],
[{}]
];
const final = result.reduce( (acc, curr) => {
return [...acc, ...curr];
}, []);
console.log(final);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

Assuming the below as your array of objects structure
let array = [[{name: 1}, {name: 2}, {name: 3}], [{name: 1}, {name: 2}, {name: 3}], [{name: 1}, {name: 2}, {name: 3}]]
let out1 = [].concat.apply([], array)
console.log(out1)
If you use latest ES then you could try with this array.flat, as mentioned by sirko in the comments
let array = [[{name: 1}, {name: 2}, {name: 3}], [{name: 1}, {name: 2}, {name: 3}], [{name: 1}, {name: 2}, {name: 3}]]
let out2 = array.flat()
console.log(out2)

Related

How to map through a deeply nested array of objects?

const my_arr = [
{id: 1, arr: [{subId: 1, value: 1}],
{id: 2, arr: [{subId: 2, value: 2}],
{id: 3, arr: [{subId: 3, value: 1}],
]
how do I map over this array my_arr and then map over arr to return an array like so:
[
{subId: 1, value: 1},
{subId: 3, value: 1},
]
basically filtering out only where values are 1 and then returning only that sub object
I've tried doing
my_arr.map((x) => x.map((y) => y.value === 1 ? y : null))
You can try this approach with flatMap and filter
const my_arr = [
{id: 1, arr: [{subId: 1, value: 1}]},
{id: 2, arr: [{subId: 2, value: 2}]},
{id: 3, arr: [{subId: 3, value: 1}]},
]
const result = my_arr.flatMap(item => item.arr).filter(item => item.value === 1)
console.log(result)
Your current approach maps over the outer array my_arr, and then uses an inner map to map over the inner array. Since .map() always returns an array, you'll end up mapping your objects from your outer array to other arrays, which you don't want. You can instead use .flatMap() which will combine/join the returned inner arrays into one array. However, rather than using .map() as your inner method though, you should use .filter() to create an array of objects that have a value of 1, which then gets merged into your resulting outer array created by the .flatMap() method:
const my_arr = [ {id: 1, arr: [{subId: 1, value: 1}]}, {id: 2, arr: [{subId: 2, value: 2}]}, {id: 3, arr: [{subId: 3, value: 1}]}, ];
const res = my_arr.flatMap(({arr}) => arr.filter(({value}) => value === 1));
console.log(res);
Since you are dealing with nested structure, you will have to get little creative.
First you will have to filter the array.
Inside it, you can use .some to check if your condition matches and return matching
Now you have the filtered list but you still need to format your output. You can use .reduce and concat arr of every item
This will be useful if you have multiple items in arr.
const my_arr = [
{id: 1, arr: [{subId: 1, value: 1}] },
{id: 2, arr: [{subId: 2, value: 2}] },
{id: 3, arr: [{subId: 3, value: 1}] },
]
const output = my_arr
.filter(({ arr }) =>
arr.some(({value}) => value === 1)
).reduce((acc, { arr }) => acc.concat(arr), [])
console.log(output)

Add unique objects to array of objects in Javascript

I have arrays of objects that look like this:
const array1 = [{id: 1, name: "John"}, {id: 2, name: "Mary"}]
const array2 = [{id: 1, name: "John"}, {id: 3, name: "Phil"}, {id: 4, name: "Sarah"}]
How can I add unique objects from array2 to array1 so it looks like this:
const array1 = [{id: 1, name: "John"}, {id: 2, name: "Mary"}, {id: 3, name: "Phil"}, {id: 4, name: "Sarah"}]
Lodash implementations are permitted. Thanks a lot.
You can use _.unionBy() function to merge unique objects from arrays.
const array1 = [{id: 1, name: "John"}, {id: 2, name: "Mary"}];
const array2 = [{id: 1, name: "John"}, {id: 3, name: "Phil"}, {id: 4, name: "Sarah"}];
console.log(_.unionBy(array1, array2, 'id'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
Using native array functions you can get the desired result as follows:
Concat both arrays first using .concat()
Use .reduce() to create the resultant object having ids as keys and values as relevant object. If already added an object then skip the others with same ids.
Use Object.values() to get an array of the objects from the resultant object.
Demo:
const array1 = [{id: 1, name: "John"}, {id: 2, name: "Mary"}],
array2 = [{id: 1, name: "John"}, {id: 3, name: "Phil"}, {id: 4, name: "Sarah"}];
const result = Object.values(
array1.concat(array2).reduce((r, c) => (r[c.id] = r[c.id] || c, r), {})
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can also do it in one line via native Map object and reduce:
const arr1 = [{id: 1, name: "John"}, {id: 2, name: "Mary"}]
const arr2 = [{id: 1, name: "John"}, {id: 3, name: "Phil"}, {id: 4, name: "Sarah"}]
const result = [...[...arr1, ...arr2]
.reduce((r, c) => (r.set(c.id, c), r), new Map()).values()]
console.log(result)

Get the JSON objects that are not present in another array

I have two arrays.
array1 = [
{'id':1},
{'id': 2}
]
and
array2 = [
{'idVal':1},
{'idVal': 2},
{'idVal': 3},
{'idVal': 4}
]
I need a optimal way, lodash if possible so that i can compare these two arrays and get a result array that has object present in array2 and not in array1. The keys have different name in both arrays. So the result will be,
res = [
{'idVal': 3},
{'idVal': 4}
]
Use _.differenceWith() with a comparator method. According to the docs about _.difference() (differenceWith is based on difference):
Creates an array of array values not included in the other given
arrays using SameValueZero for equality comparisons. The order and
references of result values are determined by the first array.
So array2 should be the 1st param passed to the method.
var array1 = [
{'id': 1},
{'id': 2}
];
var array2 = [
{'idVal': 1},
{'idVal': 2},
{'idVal': 3},
{'idVal': 4}
];
var result = _.differenceWith(array2, array1, function(arrVal, othVal) {
return arrVal.idVal === othVal.id;
});
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Using ES6
const result = array2.filter(item => !array1.find(i => i.idVal === item.id))
var array1 = [
{'id':1},
{'id': 2},
{'id': 3},
{'id': 4}
]
var array2 = [
{'id':1},
{'id': 3},
{'id': 4}
]
notInArray2 = array1.reduce( function(acc, v) {
if(!array2.find(function (vInner) {
return v.id === vInner.id;
})){
acc.push(v);
}
return acc
}, []);
console.log(JSON.stringify(notInArray2))
Here's an optimized solution, not using lodash though. I created a search index containing just the values of array1, so that you can look up elements in O(1), rather than going through the entire array1 for every element in array2.
Let m be the size of array1 and n be the size of array2. This solution will run in O(m+n), as opposed to O(m*n) that you would have without prior indexing.
const array1 = [
{'id':1},
{'id': 2}
];
const array2 = [
{'idVal':1},
{'idVal': 2},
{'idVal': 3},
{'idVal': 4}
];
const array1ValuesIndex = {};
array1.forEach(entry => array1ValuesIndex[entry.id] = true);
const result = array2.filter(entry => !array1ValuesIndex[entry.idVal]);
console.log(result);
array1 = [
{'id':1},
{'id': 2}
]
array2 = [
{'idVal':1},
{'idVal': 2},
{'idVal': 3},
{'idVal': 4}
]
var array1Keys=array1.map(function(d1){ return d1.id});
var result =array2.filter(function(d){ return array1Keys.indexOf(d.idVal)==-1 })
console.log(result);

Finding a key in an object by using values from an array

I have an array which is dynamically created by selecting items from a list:
[2, 4]
I also have an array of objects:
[{id: 1, name: "Param1"}, {id: 2, name: "Param2"}, {id: 3, name: "Param3"}, {id: 4, name: "Param4"}]
What I need to do is use the values in the first array to match against the ids in the objects in the second array and return those objects.
Help with this would be much appreciated
Thanks for your time
You can use this ES6 code, which turns the first array to a Set to allow fast lookup, and then applies the Array filter method, specifically intended for this purpose:
var select = [2, 4];
var data = [{id: 1, name: "Param1"}, {id: 2, name: "Param2"},
{id: 3, name: "Param3"}, {id: 4, name: "Param4"}]
var selectSet = new Set(select);
var result = data.filter( obj => selectSet.has(obj.id) );
console.log(result);
You can just use for loop as Liam's comment, or you can use the filter method of array like this:
var keys = [2, 4];
var objs = [{id: 1, name: "Param1"}, {id: 2, name: "Param2"}, {id: 3, name: "Param3"}, {id: 4, name: "Param4"}];
function filterById(obj) {
return keys.indexOf(obj.id) != -1;
}
var newArr = objs.filter(filterById);
The newArr is the result you want.

Compare the elements of two arrays by Id and remove the elements from the one array that are not presented in the other

I have two arrays of objects like this:
var arr1 = [{Id: 1, Name: "Test1"}, {Id: 2, Name: "Test2"}, {Id: 3, Name: "Test3"}, {Id: 4, Name: "Test4"}]
var arr2 = [{Id: 1, Name: "Test1"}, {Id: 3, Name: "Test3"}]
I need to compare the elements of the two arrays by Id and remove the elements from arr1 that are not presented in arr2 ( does not have element with that Id). How can I do this ?
var res = arr1.filter(function(o) {
return arr2.some(function(o2) {
return o.Id === o2.Id;
})
});
shim, shim, shim.
You can use a function that accepts any number of arrays, and returns only the items that are present in all of them.
function compare() {
let arr = [...arguments];
return arr.shift().filter( y =>
arr.every( x => x.some( j => j.Id === y.Id) )
)
}
var arr1 = [{Id: 1, Name: "Test1"}, {Id: 2, Name: "Test2"}, {Id: 3, Name: "Test3"}, {Id: 4, Name: "Test4"}];
var arr2 = [{Id: 1, Name: "Test1"}, {Id: 3, Name: "Test3"}, {Id: 30, Name: "Test3"}];
var arr3 = [{Id: 1, Name: "Test1"}, {Id: 6, Name: "Test3"}, {Id: 30, Name: "Test3"}];
var new_arr = compare(arr1, arr2, arr3);
console.log(new_arr);
function compare() {
let arr = [...arguments]
return arr.shift().filter( y =>
arr.every( x => x.some( j => j.Id === y.Id) )
)
}
Making use of a hash (a Set) will give a performance gain:
var arr1 = [{Id: 1, Name: "Test1"}, {Id: 2, Name: "Test2"},
{Id: 3, Name: "Test3"}, {Id: 4, Name: "Test4"}];
var arr2 = [{Id: 1, Name: "Test1"}, {Id: 3, Name: "Test3"}];
arr1 = arr1.filter(function (el) {
return this.has(el.Id);
}, new Set(arr2.map(el => el.Id)));
console.log(arr1);
A new Set is created that gets the Id values from arr2:
"1","3"
That Set is passed as the thisArg to filter, so that within the filter callback it is available as this.

Categories

Resources