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);
Related
I've found some good answers about how getting an index of an array with indexOf. However, this doesn't suit me since I must return the the index of the parent array that contains a child array which contains an object with certain id.
This would be a sample array:
[
[{id: 1}],
[{id: 2}],
[
{id: 3}
{id: 4}
],
[
{id: 5},
{id: 6}
],
[{id: 7}],
]
For example, if I'd like to find the index of the id : 4 the index would be 2.
I've thought about a map inside the findIndex method:
array.findIndex((el) => el.map((e) => e.id === noteId )));
But have not found much success yet.
As Andy Ray commented, a map doesnt return a true value.
so the correct way to do it is this:
array.findIndex((el) => el.some((e) => e.id === noteId )));
const array = [
[{id: 1}],
[{id: 2}],
[
{id: 3},
{id: 4},
],
[
{id: 5},
{id: 6}
],
[{id: 7}],
]
const noteId = 3;
console.log(array.findIndex((el) => el.some((e) => e.id === noteId )));
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)
Is it possible in some way to filter let's say such an array of object arrays:
[[{id: 1}, {id: 2}, {id: 3}], [{id:6}, {id: 2}], [{id: 2}, {id: 1}, {id: 9}, {id: 3}]]
To get array of objects which all arrays have the same property (id), so in this case it output will be:
[{id: 2}] // becasue this id is the same in all three subarrays
I've only try intersectionBy from loadash but it seems to work in completely other way :/
I would take one array (it's enough to take one because if the property is not there its already not common), in this example I'm taking the first one but probably more efficient will be picking the shortest one.
iterate over the array and check for each object if its common to all other arrays.
const arr = [[{id: 1}, {id: 2}, {id: 3}], [{id:6}, {id: 2}], [{id: 2}, {id: 1}, {id: 9}, {id: 3}]];
let firstArray = arr.shift();
const result = firstArray.reduce((common, item)=>{
if (arr.every(inner => inner.some(_item => _item.id === item.id))) {
common.push(item);
}
return common;
},[])
console.log(result);
Using Ramda:
const input = [[{id: 1}, {id: 2}, {id: 3}], [{id:6}, {id: 2}], [{id: 2}, {id: 1}, {id: 9}, {id: 3}]];
R.intersection(...input);
You can use array reduce,forEach , findIndex and sort to get the most common object. In first inside the reduce callback use forEach to iterate each of the child array and then use findIndex to find if in accumulator array , there exist an object with same id. If it does not exist create a new object with key id & occurrence. If it exist then increase the value of occurrence. This will give the most common id, even if an id is not present in few child array
let data = [
[{id: 1}, {id: 2}, { id: 3}],
[{id: 6}, {id: 2}],
[{id: 2}, {id: 1}, {id: 9}, { id: 3}]
];
let obj = data.reduce((acc, curr) => {
curr.forEach((item) => {
let getInd = acc.findIndex((elem) => {
return elem.id === item.id
});
if (getInd === -1) {
acc.push({
id: item.id,
occurence: 1
})
} else {
acc[getInd].occurence += 1;
}
})
return acc;
}, []).sort((a, b) => {
return b.occurence - a.occurence;
});
console.log(obj[0])
var arr = [
[{id: 1}, {id: 2}, {id: 3}],
[{id:6}, {id: 2}],
[{id: 2}, {id: 1}, {id: 9}, {id: 3}]
]
var obj = {};
var arrLength = arr.length;
arr.forEach((val,index) => {
val.forEach((item) =>{
if(index == 0){
if(!obj.hasOwnProperty(item.id)){
obj[item.id] = 1;
}
}else{
if(obj.hasOwnProperty(item.id)){
obj[item.id] = obj[item.id] + 1;
}else{
return;
}
}
});
});
var output = [];
for (const property in obj) {
if(obj[property] == arrLength){
output.push({
id: property
})
}
}
console.log(output);
My approach is similar to that of naortor, but with an attempt to be more generic.
const intersection = (pred) => (as, bs) =>
as .filter (a => bs .some (b => pred (a, b)))
const intersectionAll = (pred) => (xs) =>
xs.length ? xs .reduce (intersection (pred)) : []
const input = [[{id: 1}, {id: 2}, {id: 3}], [{id:6}, {id: 2}], [{id: 2}, {id: 1}, {id: 9}, {id: 3}]]
const eqIds = (a, b) => a .id == b .id
console .log (
intersectionAll (eqIds) (input)
)
.as-console-wrapper {min-height: 100% !important}
This version requires you to say how you identify two equal values. (We will check that they have the same id, but any binary predicate function is allowed.) This function is passed to intersection which returns a function that takes two arrays and finds all the element in common between those two. intersectionAll wraps this behavior up, folding intersection over an array of arrays.
This breakdown is useful, as intersection is a useful function on its own too. And abstracting out the id check into a function you need to supply means these functions are much more generic.
I have an array, which contains array of objects. I need to extract the property value "id" of items that have objects.
Example of array:
let myArray = [
[ {id: "1"}, {id: "2"} ],
[],
[],
[ {id: "3"} ]
]
How can I extract and create an array like this:
["1", "2", "3"]
I tried this:
tagIds = myArray.map(id =>{id})
You can use reduce to flatten the array and use map to loop thru the array and return the id.
let myArray = [
[{id: "1"}, {id: "2"}],
[],
[],
[{id: "3"}],
];
let result = myArray.reduce((c, v) => c.concat(v), []).map(o => o.id);
console.log(result);
Another way with simple nested loops:
let myArray = [
[ {id: "1"}, {id: "2"} ],
[],
[],
[ {id: "3"} ]
]
//----------------------------------
let newArray=[];
for (let i=0;i<myArray.length;i++){
for (let j=0;j<myArray[i].length;j++){
newArray.push(myArray[i][j].id);
}
}
console.log(newArray); //outputs ['1','2','3']
You can use .concat() to create array of single objects and then .map() to extract ids:
let myArray = [
[{id: "1"}, {id: "2"}], [], [], [{id:"3"}]
];
let result = [].concat(...myArray).map(({ id }) => id);
console.log(result);
Docs:
Array.prototype.concat()
Array.prototype.map()
Spread Syntax
Here is my solution:
let a = myArray.flat(100) // you can put (3) or (10) in here, the higher the flatter the array
let b = a.map(
function(value){
return parseInt(value.id)
}
)
console.log(b)
You can also write a recursive function to make this work with any number of arrays, for example:
function extractIds(arr) {
return arr.reduce((a, item) => {
if (Array.isArray(item)) {
return [
...a,
...extractIds(item)
];
}
return [
...a,
item.id
];
}, [])
}
extractIds([{id: 1}, [{id: 2}], {id: 3}, [{id: 4}, [{id: 5}, [{id: 6}]]]])
the return of extractIds will be [1, 2, 3, 4, 5, 6].
Notice that without the recursive part you would end up with something like this: [1, 2, [3, {id: 4}, [{id: 5}]]] (Not exactly like this, but just as an example).
I have an array as :
items=[{'id':1},{'id':2},{'id':3},{'id':4}];
How should I add a new pair {'id':5} to the array?
Use .push:
items.push({'id':5});
.push() will add elements to the end of an array.
Use .unshift() if need to add some element to the beginning of array i.e:
items.unshift({'id':5});
Demo:
items = [{'id': 1}, {'id': 2}, {'id': 3}, {'id': 4}];
items.unshift({'id': 0});
console.log(items);
And use .splice() in case you want to add object at a particular index i.e:
items.splice(2, 0, {'id':5});
// ^ Given object will be placed at index 2...
Demo:
items = [{'id': 1}, {'id': 2}, {'id': 3}, {'id': 4}];
items.splice(2, 0, {'id': 2.5});
console.log(items);
Sometimes .concat() is better than .push() since .concat() returns the new array whereas .push() returns the length of the array.
Therefore, if you are setting a variable equal to the result, use .concat().
items = [{'id': 1}, {'id': 2}, {'id': 3}, {'id': 4}];
newArray = items.push({'id':5})
In this case, newArray will return 5 (the length of the array).
newArray = items.concat({'id': 5})
However, here newArray will return [{'id': 1}, {'id': 2}, {'id': 3}, {'id': 4}, {'id': 5}].
If you're doing jQuery, and you've got a serializeArray thing going on concerning your form data, such as :
var postData = $('#yourform').serializeArray();
// postData (array with objects) :
// [{name: "firstname", value: "John"}, {name: "lastname", value: "Doe"}, etc]
...and you need to add a key/value to this array with the same structure, for instance when posting to a PHP ajax request then this :
postData.push({"name": "phone", "value": "1234-123456"});
Result:
// postData :
// [{name: "firstname", value: "John"}, {name: "lastname", value: "Doe"}, {"name":"phone","value":"1234-123456"}]
New solution with ES6
Default object
object = [{'id': 1}, {'id': 2}, {'id': 3}, {'id': 4}];
Another object
object = {'id': 5};
Object assign ES6
resultObject = {...obj, ...newobj};
Result
[{'id': 1}, {'id': 2}, {'id': 3}, {'id': 4}, {'id': 5}];