Best way to find the difference between 2 arrays of objects - javascript

I have these 2 arrays of objects.
Sorry that I post the image because I want you guys to quickly understand my points.
What is the best way to compare 2 arrays of objects and look for what is not in it?
I can do 2 levels for loops and an if-check, but I'm not sure if it is the best approach.
I am seeking a better performance JS way to achieve something like this.
This is what I am looking to extract while comparing arr1 & arr2.
{
"id": 4,
"name": "Date and Time"
}

One way is to concatenate both arrays together, then iterate and filter to see if that id exists in both arrays. If it doesn't exist in both arrays, it's extra.
a1.concat(a2).filter(a => a1.findIndex(f => f.id === a.id) == -1 || a2.findIndex(f => f.id === a.id) == -1)
let arr1 = [{"id": 1,"name": "Date and Time"},{"id": 2,"name": "Date and Time"},{"id": 3,"name": "Date and Time"},{"id": 4,"name": "Date and Time"}]
let arr2 = [{"id": 1,"name": "Date and Time"},{"id": 2,"name": "Date and Time"},{"id": 3,"name": "Date and Time"}]
const findMissing = (a1, a2) => a1.concat(a2).filter(a => a1.findIndex(f => f.id === a.id) == -1 || a2.findIndex(f => f.id === a.id) == -1)
console.log(findMissing(arr1, arr2))

Different ways to achieve this requirement. I also created a performance check based on all the below 3 solutions here. Kindly run this test suite and based on the result you can use any of the below solution in your project.
Filtered out the array by using Array.filter() method and find the id in the another array by using Array.find() method.
const arr1 = [{
id: 1,
name: "Weather"
}, {
id: 2,
name: "Geo Location"
}, {
id: 3,
name: "Device"
}];
const arr2 = [{
id: 1,
name: "Weather"
}, {
id: 2,
name: "Geo Location"
}, {
id: 3,
name: "Device"
}, {
id: 4,
name: "Date and Time"
}];
const res = arr2.filter((obj) => !arr1.find(({ id }) => obj.id === id));
console.log(res);
By using Array.includes() method.
const arr1 = [{
id: 1,
name: "Weather"
}, {
id: 2,
name: "Geo Location"
}, {
id: 3,
name: "Device"
}];
const arr2 = [{
id: 1,
name: "Weather"
}, {
id: 2,
name: "Geo Location"
}, {
id: 3,
name: "Device"
}, {
id: 4,
name: "Date and Time"
}];
const IDArray = arr1.map(obj => obj.id);
const res = arr2.filter(obj => !IDArray.includes(obj.id));
console.log(res);
Use Array.some() along with Array.filter() method.
const arr1 = [{
id: 1,
name: "Weather"
}, {
id: 2,
name: "Geo Location"
}, {
id: 3,
name: "Device"
}];
const arr2 = [{
id: 1,
name: "Weather"
}, {
id: 2,
name: "Geo Location"
}, {
id: 3,
name: "Device"
}, {
id: 4,
name: "Date and Time"
}];
const res = arr2.filter(({ id }) => !arr1.some(x => x.id == id))
console.log(res)

Related

how to find data in array vuejs

I want to find data by value, but the value is an array .. how?
mylokasi [
{
id: 1 ,
name : koko
},
{
id: 2 ,
name : doni
},
{
id: 3 ,
name : dika
},
{
id: 4 ,
name : ujang
},
]
mylokasi.find(p => p.id== [2,3,4,3]).name
I want to display all the data in the array [2,3,4,3]
result value so : doni,dika,ujang,dika
You can use the filter and map functions:
mylocasi
.filter(item => [2, 3, 4, 3].includes(item.id))
.map(item => item.name)
Using map() and find() you can achieve your goal !
Try this code it's help you !
let mylokasi = [{ id: 1, name: 'koko' }, { id: 2, name: 'doni' }, { id: 3, name: 'dika' }, { id: 4, name: 'qotol' }];
let arr = [2, 3, 4, 3];
let res = arr.map((id) => (mylokasi.find(x => x.id == id).name));
console.log(res, 'res');

How to add property value from one array of objects into another (for the matching objects) in JS

I am trying to filter array of objects based on another array of objects and after finding all matching items I want to set property and value from the first array object into corresponding object in the second array:
const searchedProducts = products.filter(product =>
uniqueProducts.some(
uniqueProduct =>
product.productId === uniqueProduct.productId,
),
)
After here I need to set product.productName for each unique product object under productName property.
Ho such a thing can be achieved in a better way?
This is probably most straightforward using reduce() combined with find() to both retrieve and verify that the second array contains each object.
const uniqueProducts = [
{id: 3, from: 'uniqueProducts', name: 'Unique 1'},
{id: 12, from: 'uniqueProducts', name: 'Unique 12'}
];
const products = [
{id: 1, from: 'products', name: 'Product 1'},
{id: 2, from: 'products', name: 'Product 2'},
{id: 9, from: 'products', name: 'Product 9'},
{id: 12, from: 'products', name: 'Product 12'},
];
const output = products.reduce((a, p) => {
const uP = uniqueProducts.find(u => u.id === p.id);
if (uP) a.push({...p, name: uP.name});
return a;
}, []);
console.log(output);
I have inventory where I have to add a price property and take its value from products array so I did this,
inventory = [
{
"productId": 1,
"quantity": 100,
"name": "2 Yolks Noodles",
"image": "twoeggnoodles.jpg",
}
]
Products = [
{
"id": 1,
"quantity": 100,
"name": "2 Yolks Noodles",
"image": "twoeggnoodles.jpg",
"price": 34.95
}
]
let product:any = [];
products.map((prod:any)=>{
const index:any = inventory.find((u:any) => u.productId === prod.id);
// console.log("item", index, '-', prod)
if(index){
product.push({...index, price: prod.price});
}
return prod
})
});

Common values in array of arrays - lodash

I have an array that looks like this:
const myArray = [
[
{id: 1, name: 'Liam'},
{id: 2, name: 'Oliver'},
{id: 3, name: 'Jake'},
],
[
{id: 1, name: 'Liam'},
{id: 2, name: 'Oliver'},
{id: 4, name: 'Joe'},
],
]
I need to find common elements by id, and return them in an array that would look something like this:
[
{id: 1, name: 'Liam'},
{id: 2, name: 'Oliver'},
]
If there isn't any way to do it with lodash, just JS could work too.
Note that I do not know how many of these arrays I will have inside, so it should work for any number.
You can use lodash's _.intersectionBy(). You'll need to spread myArray because _intersectionBy() expect arrays as arguments, and not a single array of array:
const myArray = [[{"id":1,"name":"Liam"},{"id":2,"name":"Oliver"},{"id":3,"name":"Jake"}],[{"id":1,"name":"Liam"},{"id":2,"name":"Oliver"},{"id":4,"name":"Joe"}]]
const result = _.intersectionBy(...myArray, 'id')
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"></script>
A vanilla solution can be as simple as a filter() call on the first element of the array checking to see that every() subsequent element contains some() elements that match.
const [srcElement, ...compArray] = [...myArray];
const intersection = srcElement.filter(o => (
compArray.every(arr => arr.some(p => p.id === o.id)))
);
console.log(intersection)
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script>
const myArray = [
[{ id: 1, name: 'Liam' }, { id: 2, name: 'Oliver' }, { id: 3, name: 'Jake' }],
[{ id: 1, name: 'Liam' }, { id: 2, name: 'Oliver' }, { id: 4, name: 'Joe' }],
[{ id: 1, name: 'Liam' }, { id: 2, name: 'Oliver' }, { id: 5, name: 'Dean' }, { id: 6, name: 'Mara' }]
]
</script>
Use nested forEach loops and Set. Go over each sub-array and find out the common items so far.
const intersection = ([firstArr, ...restArr]) => {
let common = new Set(firstArr.map(({ id }) => id));
restArr.forEach((arr) => {
const newCommon = new Set();
arr.forEach(({ id }) => common.has(id) && newCommon.add(id));
common = newCommon;
});
return firstArr.filter(({ id }) => common.has(id));
};
const myArray = [
[
{ id: 1, name: "Liam" },
{ id: 2, name: "Oliver" },
{ id: 3, name: "Jake" },
],
[
{ id: 1, name: "Liam" },
{ id: 2, name: "Oliver" },
{ id: 4, name: "Joe" },
],
[
{ id: 2, name: "Oliver" },
{ id: 4, name: "Joe" },
],
];
console.log(intersection(myArray));
Nowadays vanilla ES is pretty powerful to work with collections in a functional way even without the help of utility libraries.
You can use regular Array's methods to get a pure JS solution.
I've created two examples with pure JS.
Of course, there could be more approaches as well. And if you already use Lodash in your application, probably it would be better to just use its high-level implementation in form of _.intersectionBy() proposed above to reduce the code complexity.
const myArray = [
[
{id: 1, name: 'Liam'},
{id: 2, name: 'Oliver'},
{id: 3, name: 'Jake'},
],
[
{id: 1, name: 'Liam'},
{id: 2, name: 'Oliver'},
{id: 4, name: 'Joe'},
],
];
// Regular functional filter-reduce
const reducer = (accum, x) => {
return accum.findIndex(y => x.id == y.id) < 0
? [...accum, x]
: accum;
};
const resultFilterReduce = myArray
.flat()
.filter(x => myArray.every(y => y.findIndex(obj => obj.id === x.id) > -1))
.reduce(reducer, []);
console.log(resultFilterReduce);
// Filter-reduce with using of "HashMap" to remove duplicates
const resultWithHashMap = Object.values(
myArray
.flat()
.filter(x => myArray.every(y => y.findIndex(obj => obj.id === x.id) > -1))
.reduce((accum, x) => {
accum[x.id] = x;
return accum;
}, {})
);
console.log(resultWithHashMap);

Javascript compare two JSON arrays and return key of the unmatched value

I have two JSON arrays, would like to know the key which don't match. I don't need the value.
Example:
livetable: [
{ id: 1, name: "Sandra" },
{ id: 2, name: "John" },
],
backupTable: [
{ id: 1, name: "Sandra" },
{ id: 2, name: "Peter" },
],
I can get the key/value pair which is diffrent with this Lodash script:
difference = _.differenceWith(livetable,backupTable,_.isEqual)
But I would just need the key, in this example "name" for "id: 2" is not matching, so I would need to get the "name" key to new array/variable.
(Using VUE CLI)
EDIT: Added example of current code output.
var livetable = [{"id": 1, "name": "Sandra", "id": 2, "name": "John"}]
var backupTable = [{"id": 1, "name": "Sandra", "id": 2, "name": "Peter"}]
console.log(_.differenceWith(backupTable,livetable,_.isEqual))
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>
This will output the key:value pair, but I would just need the key which is diffrent.
I think I understand what you're trying to do. There are some unknowns though, like what should happen if there is a missing record in the second data set?
This solution assumes each table of data has the same amount of records and the records have the same IDs.
// define data
const livetable = [
{ id: 1, name: "Sandra" },
{ id: 2, name: "John" }
]
const backupTable = [
{ id: 1, name: "Sandra" },
{ id: 2, name: "Peter" }
]
const getDifferentRecordsByID = (sourceRecords, compareRecords) => {
// simple utility function to return a record object matching by ID
const findComparisionRecord = id => compareRecords.find(compareRecord => compareRecord.id === id)
// using the utility function, we can filter out any mismatching records by comparing name
return sourceRecords
.filter(sourceRecord => sourceRecord.name !== findComparisionRecord(sourceRecord.id).name)
// then map over all the records and just pull out the ID
.map(record => record.id)
}
console.log(getDifferentRecordsByID(livetable, backupTable)) // [2]
Here is working VUE code for my problem.
Function returns [ "name" ], which is exactly what I need.
data() {
return {
livetable: [{ id: 1, name: "Sandra" },{ id: 2, name: "John" }],
backupTable: [{ id: 1, name: "Sandra" },{ id: 2, name: "Peter" }],
difColumns: null,
};
},
methods: {
test3() {
let resultArray = []
this.livetable.forEach((array1, index) => {
const array2 = this.backupTable[index];
resultArray.push(this._.reduce(array1, (result, value, key) => this._.isEqual(value, array2[key]) ? result : result.concat(key), []))
});
this.difColumns = resultArray[0]
}
},

Return array of objects (from array of objects)

I have the following data and I want to return an array (of objects) of years that are distinct.
I tried the following function but I'm getting an array within an array.
const data = [{
id: 1,
name: "test1",
years: [{
id: 1,
name: "year1"
}, {
id: 2,
name: "year2"
}]
},
{
id: 2,
name: "test2",
years: [{
id: 1,
name: "year1"
}]
},
]
let years = data.map((s) => {
return s.years
})
let distinctYears = Array.from(new Set(years.map(c => c.id))).map(id => {
return {
id: id,
name: years.find(c => c.id === id).name,
}
})
console.log(distinctYears);
desired outcome:
[
{id: 1, name: "year1"},
{id: 2, name: "year2"}
]
Since s.years() is an array, and data.map() returns an array of the results, years is necessarily an array of arrays.
Instead of using .map(), use .reduce() to concatenate them.
const data = [{
id: 1,
name: "test1",
years: [{
id: 1,
name: "year1"
}, {
id: 2,
name: "year2"
}]
},
{
id: 2,
name: "test2",
years: [{
id: 1,
name: "year1"
}]
},
];
const years = data.reduce((a, {
years
}) => a.concat(years), []);
let distinctYears = Array.from(new Set(years.map(c => c.id))).map(id => {
return {
id: id,
name: years.find(c => c.id === id).name,
}
});
console.log(distinctYears);
There's so many ways you can go about doing this. Here's one, it's not a one-liner but its broken down to parts to help us understand whats going on.
Your dataset:
let data =
[
{
id: 1,
name: "test1",
years: [{id: 1, name: "year1"}, {id: 2, name: "year2"} ]
},
{
id: 2,
name: "test2",
years: [{id: 1, name: "year1"} ]
},
]
Use .flatMap() to create a one-level array with all items:
let allItems = data.flatMap((item) => {
return item.years.map((year) => {
return year
})
})
Getting distinct items:
let distinct = []
allItems.forEach((item) => {
let matchingItem = distinct.find((match) => match.id == item.id && match.name == item.name)
if(!matchingItem){
distinct.push(item)
}
})
In Practice:
let data = [{
id: 1,
name: "test1",
years: [{
id: 1,
name: "year1"
}, {
id: 2,
name: "year2"
}]
},
{
id: 2,
name: "test2",
years: [{
id: 1,
name: "year1"
}]
},
]
let allItems = data.flatMap((item) => {
return item.years.map((year) => {
return year
})
})
let distinct = []
allItems.forEach((item) => {
let matchingItem = distinct.find((match) => match.id == item.id && match.name == item.name)
if (!matchingItem) {
distinct.push(item)
}
})
console.log(distinct)

Categories

Resources