Comparing a particular key in 2 array of objects [duplicate] - javascript

This question already has answers here:
How to get the difference between two arrays of objects in JavaScript
(22 answers)
Closed 3 years ago.
Is there a way with lodash, where in result I do not have an object that satisfies a particular condition. For example,
o1 = [
{name: "a", id: 2, key: 33},
..,
]
o2 = [
{name: "ab", id: 2, key: 133}
]
Is there a way with lodash where the resultant array only includes the object that does not have the ids already present in o2. For example, resultant object after comparing o1 and o2 must not have the object from o2 because id=2 already exists in o1.

You can use _.differenceBy() and use the id of the point of reference:
const o1 = [{id: 1, name: 'a'},{id: 2, name: 'b'},{id: 3, name: 'c'}]
const o2 = [{id: 1, name: 'b'}]
const result = _.differenceBy(o1, o2, 'id')
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Maybe _.differenceWith?
const o1 = [
{id: 1, name: "a"},
{id: 2, name: "b"},
{id: 3, name: "c"},
]
const o2 = [
{id: 1, name: "b"},
]
const diffed = _.differenceWith(o1, o2, (o1, o2) => o1.id === o2.id)
console.log(diffed)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

You could do this without lodash by using .filter() and creating a Set. Firstly, you can create a set of all the ids in o2. Then, you can filter out any objects from o1 which have an id within the set. By using a set with .has() we are able to make our algorithm more efficient (than say using .includes() on an array).
See example below:
const o1 = [
{name: "a", id: 2, key: 33},
{name: "b", id: 3, key: 34},
{name: "c", id: 4, key: 34}
]
const o2 = [
{name: "d", id: 2, key: 134}
]
const o2_ids = new Set(o2.map(({id}) => id));
const result = o1.filter(({id}) => !o2_ids.has(id));
console.log(result); // includes objects with id's that appear in o1 but not in o2

<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script>
var o1 = [
{name: "a", id: 77, key: 55},
{name: "a", id: 2, key: 33},
{name: "a", id: 1, key: 55}
]
var o2 = [
{name: "ab", id: 88, key: 133},
{name: "ab", id: 2, key: 133},
{name: "ab", id: 99, key: 133}
]
//sort first
o1.sort((a, b) => {
return a.id-b.id;//sort by id
});
o2.sort((a, b) => {
return a.id-b.id;//sort by id
});
//then compare one by one
function SearchX(OO1,OO2){
var o1_compare_place=0;
var o2_compare_place=0;
while(OO2.length>o2_compare_place && OO1.length>o1_compare_place ){
if(OO2[o2_compare_place].id<OO1[o1_compare_place].id){
o2_compare_place+=1;
}else if(OO2[o2_compare_place].id>OO1[o1_compare_place].id){
o1_compare_place+=1;
}else{
return "Exist Same!";
}
}
return "Different!";
}
document.body.innerHTML = SearchX(o1,o2)
</script>
</body>
</html>
Here you are

Related

how to guet maximum value of object with same name and Id

i have an array of objects like below
[
{value: 1, id: 1, name: "x"},
{value: 5, id: 1, name: "x"},
{value: 1, id: 1, name: "y"},
{value: 8, id: 1, name: "y"},
{value: 1, id: 2, name: "x"},
{value: 3, id: 2, name: "x"},
{value: 1, id: 2, name: "y"},
{value: 4, id: 2, name: "y"}
]
i want to guet the object with max value with the same "name" and "id"
and push it in a new array ,
the expected output is like this :
[
{value: 5, id: 1, name: "x"},
{value: 8, id: 1, name: "y"},
{value: 3, id: 2, name: "x"},
{value: 4, id: 2, name: "y"},
]
thank you
You can use reduce method to do this,
const data = [
{value: 1, id: 1, name: "x"},
{value: 5, id: 1, name: "x"},
{value: 1, id: 1, name: "y"},
{value: 8, id: 1, name: "y"},
{value: 1, id: 2, name: "x"},
{value: 3, id: 2, name: "x"},
{value: 1, id: 2, name: "y"},
{value: 4, id: 2, name: "y"}
]
const res = data.reduce((prev, curr) => {
const index = prev.findIndex((item) => item.id === curr.id && item.name === curr.name);
if(index > -1) {
const obj = prev[index];
if(obj.value < curr.value) {
prev[index] = {...obj, value: curr.value};
return prev;
}
}
prev.push(curr);
return prev;
}, []);
console.log(res);
Using Array.prototype.reduce, you can group that array using id_name key pair and store the maximum values as follows.
const input = [
{value: 1, id: 1, name: "x"},
{value: 5, id: 1, name: "x"},
{value: 1, id: 1, name: "y"},
{value: 8, id: 1, name: "y"},
{value: 1, id: 2, name: "x"},
{value: 3, id: 2, name: "x"},
{value: 1, id: 2, name: "y"},
{value: 4, id: 2, name: "y"}
];
const groupBy = input.reduce((acc, cur) => {
const key = `${cur.id}_${cur.name}`;
if (!acc[key]) {
acc[key] = cur;
}
if (acc[key].value < cur.value) {
acc[key].value = cur.value;
}
return acc;
}, {});
const output = Object.values(groupBy);
console.log(output);
Reduce is used to return a new value that is basically accumulator (adds on previous value) from all the items in the array. Here we can use it to group items using specific key. As you wrote you want to have items showing a record with biggest value having same id and name, these values can be taken as a key (lets look at them as composite private keys of this object).
On each iteration, we check if there is already an object with that key added to the list, if it wasn't we add the object we are now on (during iteration) or if it was already added if its value is smaller than the current object we are on. If the value is smaller, we override the object with the current one.
In the end, we use JS Object.values method that strips away the keys and returns only the values of the object.
const list = [
{value: 1, id: 1, name: "x"},
{value: 5, id: 1, name: "x"},
{value: 1, id: 1, name: "y"},
{value: 8, id: 1, name: "y"},
{value: 1, id: 2, name: "x"},
{value: 3, id: 2, name: "x"},
{value: 1, id: 2, name: "y"},
{value: 4, id: 2, name: "y"}
];
const groupedResults = list.reduce((result, currentObject) => {
const currentKey = currentObject.id + currentObject.name;
if (!result[currentKey] || result[currentKey].value < currentObject.value) { /* Here we check if object with certain key was assigned to previously or if it was is the value smaller than of the object that we are currently seeing */
result[currentKey] = Object.assign({}, currentObject) //We need to do copy of the object (it can be also done using object destructuring) in order to have a new object that will not be bound by reference with the original one
};
return result;
}, {});
const requestedList = Object.values(groupedResults);
console.log(requestedList)

Comparing Two Arrays with Array.filter and Pushing to New Arrays Based on Common Values

I am trying to use array.filter() to compare two arrays and separate out values that the two arrays have in common, based on a certain property (id), vs. values they don't have in common. The common ids I want to push to a new array (recordsToUpdate). And I want to push the remaining elements from arr2 to a new array (recordsToInsert).
What I've tried is not working. How can I rework this to get the results I wanted? - (which in the example here should be one array of 1 common element {id: 3}, and another array of the remaining elements from arr2):
const arr1 = [{id: 1}, {id: 2}, {id: 3}];
const arr2 = [{id: 3}, {id: 4}, {id: 5}];
let recordsToUpdate = [];
let recordsToInsert = [];
recordsToUpdate = arr1.filter(e => (arr1.id === arr2.id));
recordsToInsert = ?
console.log('recordsToUpdate: ', recordsToUpdate);
console.log('recordsToInsert: ', recordsToInsert);
The desired result should be:
recordsToUpdate = [{id: 3}];
recordsToInsert = [{id: 4}, {id: 5}];
Try this, which uses Array.prototype.find to test for whether an object exists in arr2 with a given id:
const arr1 = [{id: 1}, {id: 2}, {id: 3}];
const arr2 = [{id: 3}, {id: 4}, {id: 5}];
const recordsToUpdate = arr1.filter(e => arr2.find(obj => obj.id === e.id) !== undefined);
const recordsToInsert = arr1.filter(e => arr2.find(obj => obj.id === e.id) === undefined);
console.log('recordsToUpdate: ', recordsToUpdate);
console.log('recordsToInsert: ', recordsToInsert);
Update to Robin post using some instead of find. It is just other way around.
const arr1 = [{id: 1}, {id: 2}, {id: 3}];
const arr2 = [{id: 3}, {id: 4}, {id: 5}];
const recordsToUpdate = arr1.filter(e => arr2.some(obj => obj.id === e.id));
const recordsToInsert = arr2.filter(e => !arr1.some(obj => obj.id === e.id));
console.log('recordsToUpdate: ', recordsToUpdate);
console.log('recordsToInsert: ', recordsToInsert);
I think this is what you are after... I added values to show the replacement. If you are doing any kind of state management, be careful as I am directly mutating the current array.
const arr1 = [
{ id: 1, v: "a" },
{ id: 2, v: "b" },
{ id: 3, v: "old" }
];
const arr2 = [
{ id: 3, v: "new" },
{ id: 4, v: "e" },
{ id: 5, v: "f" }
];
function updateRecords(currentArray, updatesArray) {
const currentIds = currentArray.map(item => item.id);
updatesArray.forEach(updateItem =>
currentIds.includes(updateItem.id)
? (currentArray[
currentIds.findIndex(id => id === updateItem.id)
] = updateItem)
: currentArray.push(updateItem)
);
return currentArray;
}
console.log(updateRecords(arr1, arr2))
This now gives the option below:
[
{
"id": 1,
"v": "a"
},
{
"id": 2,
"v": "b"
},
{
"id": 3,
"v": "new"
},
{
"id": 4,
"v": "e"
},
{
"id": 5,
"v": "f"
}
]
Putting it in a function is also something you likely want to do as you will likely use this multiple places in your code.

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)

How to extract property of array in nested array

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).

Get an item in an array to first position according to a condition

Hey I have the following array :
var ar = [{id: "F"}, {id: "G"}, {id: "Z"}, {id: "ZZ"}]
I would like to move the one with the id equals to ZZ to the first position in the array.
I know how to do it using several different functions, but I was wondering if there was an elegant solution to do it (lodash, ...)
You could use unshift() to add to start of array and splice() and findIndex() to get object by id.
var arr = [{id: "F"}, {id: "G"}, {id: "Z"}, {id: "ZZ"}]
arr.unshift(arr.splice(arr.findIndex(e => e.id == "ZZ"), 1)[0])
console.log(arr)
var ar = [{
id: "F"
}, {
id: "G"
}, {
id: "Z"
}, {
id: "ZZ"
}];
ar.sort(function(a, b) {
if (a.id === "ZZ") {
return -1;
}
if (b.id === "ZZ") {
return 1;
}
return 0;
});
console.log(ar);
How about sorting it?

Categories

Resources