How to compare two object array in javascript? - javascript

I want to compare these two object array and get the same result as the annotation.
My solution is an overlaid iteration, and I haven't come up with a better solution.
const arr1 = [
{key: 'cat', name: 'john' },
{key: 'dog', name: 'james' },
{key: 'dog', name: 'kane' }
];
const arr2 = [
{kind: 'cat', sound: 'meow', size: 'small', state: 'angry' },
{kind: 'dog', sound: 'woof', size: 'big', state: 'happy' },
{kind: 'pig', sound: 'oink', size: 'medium', state: 'sad' },
];
const result = arr1.map((ar) => {
const data = arr2.find(ar2=> {
return ar.key === ar2.kind;
})
const {sound} = data;
return Object.assign(ar, {sound});
});
console.log(result);
/* result
[
{key: 'cat', sound: 'meow', name: 'john'},
{key: 'dog', sound: 'woof', name: 'james'},
{key: 'dog', sound: 'woof', name: 'kane'},
]
*/
I want to know a better solution than this.
How can I solve it? Please let me know.

I'd first create an object of soundsByAnimalName, whose keys are the animal names and values are the sounds they make, then .map the first array and just look up the animal.key property on that object:
const arr1 = [
{key: 'cat', name: 'john' },
{key: 'dog', name: 'james' },
{key: 'dog', name: 'kane' }
];
const arr2 = [
{kind: 'cat', sound: 'meow', size: 'small', state: 'angry' },
{kind: 'dog', sound: 'woof', size: 'big', state: 'happy' },
{kind: 'pig', sound: 'oink', size: 'medium', state: 'sad' },
];
const soundsByAnimalName = arr2.reduce((a, { kind, sound }) => {
a[kind] = sound;
return a;
}, {});
const result = arr1.map(
animal => ({ ...animal, sound: soundsByAnimalName[animal.key] })
);
console.log(result);

You have the right idea. If you means "better" as a shorter way to write it, here it is :
You can use the ... spread operator to add a key to the json of the first array. And use of || operator to handle the case where there is no matching values.
const arr1 = [{
key: 'cat',
name: 'john'
},
{
key: 'dog',
name: 'james'
},
{
key: 'dog',
name: 'kane'
},
{
key: 'lama',
name: 'cartman'
}
];
const arr2 = [{
kind: 'cat',
sound: 'meow',
size: 'small',
state: 'angry'
},
{
kind: 'dog',
sound: 'woof',
size: 'big',
state: 'happy'
},
{
kind: 'pig',
sound: 'oink',
size: 'medium',
state: 'sad'
},
];
const ret = arr1.map(x => {
const {
sound = '',
size = '',
} = (arr2.find(y => y.kind === x.key) || {});
return ({
...x,
sound,
size,
});
});
console.log(ret);

Related

Filtering array based on selected object in JS

Trying to get the filtered array based on the selected object. How can I loop through damaged array which is inside the object and get the resultant array? I tried to add another condition using .map but it prints the rest of the items as well.
Below is the snippet
const inventory = [{
name: 'Jeep',
id: '100',
damaged: [{
name: 'Wrangler',
id: '200'
},
{
name: 'Sahara',
id: '201'
}
]
}, {
name: 'Audi',
id: '101',
damaged: [{
name: 'Q3',
id: '300'
}]
}]
const purchasedCars = [{
car: 'Jeep',
id: '100'
}, {
car: 'Jeep - Wrangler',
id: '200',
},
{
car: 'Jeep - Sahara',
id: '201'
},
{
car: 'Audi - Q3',
id: '300'
}
]
const selectedCar = purchasedCars[0];
const filterCars = () => {
const result = purchasedCars.filter((inv) => inv.id === selectedCar.id)
console.log('result -->', result);
}
filterCars();
Expected output is
[{
car: 'Jeep',
id: '100'
},
{
car: 'Jeep - Wrangler',
id: '200',
},
{
car: 'Jeep - Sahara',
id: '201'
}]
Could anyone please help?
Trying to read your mind here. Is this what you want?
const inventory = [{
name: 'Jeep',
id: '100',
damaged: [{
name: 'Wrangler',
id: '200'
},
{
name: 'Sahara',
id: '201'
}
]
}, {
name: 'Audi',
id: '101',
damaged: [{
name: 'Q3',
id: '300'
}]
}]
const purchasedCars = [{
car: 'Jeep',
id: '100'
}, {
car: 'Jeep - Wrangler',
id: '200',
},
{
car: 'Jeep - Sahara',
id: '201'
},
{
car: 'Audi - Q3',
id: '300'
}
]
const selectedCar = purchasedCars[0];
const filterCars = () => {
let result;
const parentItem = inventory.filter((inv) => inv.id === selectedCar.id)[0];
if ("damaged" in parentItem) {
result = [selectedCar, ...(parentItem.damaged)];
}
console.log('result -->', result);
}
filterCars();
Note that if you can have more nested car types in the damaged property you would you to call filterCars recursively and pass in the car object. If you also want to filters items that may also be present in the damaged property, then you would first need to use the flatMap method (before the filter).

How to compare the sameness of object entries of 2 arrays and how to create a merger of both objects with custom properties of the found same object?

I am trying to compare 2 objects by their property and the values Strictly using forloop. If the value of the "name" or another property matches up with each other, I want to push the property and value to value3.
Once value3 is logged, I want the response like this:
{
name: 'dog',
surname: 'good',
skills: 'programming',
age: '22'
},
{
name: 'cat',
surname: 'soft',
skills: 'engineer'
age: '12'
},
{
name: 'elephant',
surname: 'big',
skills: 'programming'
age: '23'
}
Here is the code:
var values1 = [
{
name: 'dog',
surname: 'good',
skills: 'programming'
},
{
name: 'cat',
surname: 'soft',
skills: 'engineer'
},
{
name: 'elephant',
surname: 'big',
skills: 'programming'
}
]
var values2 = [
{
name: 'cat',
food: 'fish',
age: '12'
},
{
name: 'elephant',
food: 'leafs',
age: '13'
},
{
lastname: 'dog',
food: 'treats',
age: '22'
}
]
// push into this empty object array
var values3 = [{}]
console.log(values3)
The most generic approach which fulfills all of the OP's requirements should be based on Array.prototype.reduce. Its advantage comes with utilizing the additionally passed optional initial value as kind of configurable collector/accumulator object which will carry all the needed additional information / functions / result. Thus one can provide a reusable function with a customizable context/environment which one can adapt to ones needs.
var values1 = [{
name: 'dog',
surname: 'good',
skills: 'programming',
}, {
name: 'cat',
surname: 'soft',
skills: 'engineer',
}, {
name: 'elephant',
surname: 'big',
skills: 'programming',
}];
var values2 = [{
name: 'cat',
food: 'fish',
age: '12'
}, {
name: 'elephant',
food: 'leafs',
age: '13'
}, {
lastname: 'dog',
food: 'treats',
age: '22'
}];
function mergeItemsOfSameEntry(collector, item) {
const {
getSameEntryValue,
getMergeSubType,
comparisonItems,
result
} = collector;
const itemValue = getSameEntryValue(item);
const comparisonItem = comparisonItems
.find(cItem => getSameEntryValue(cItem) === itemValue);
if (comparisonItem !== null) {
result.push({
...item,
...getMergeSubType(comparisonItem),
});
}
return collector;
}
const values3 = values1.reduce(mergeItemsOfSameEntry, {
getSameEntryValue: item => item.name ?? item.lastname,
getMergeSubType: ({ age }) => ({ age }),
comparisonItems: values2,
result: [],
}).result;
console.log({ values3 });
.as-console-wrapper { min-height: 100%!important; top: 0; }
If you just want the key and value pair, you can do something like this:
var values1 = [
{
name: 'dog',
surname: 'good',
skills: 'programming'
},
{
name: 'cat',
surname: 'soft',
skills: 'engineer'
},
{
name: 'elephant',
surname: 'big',
skills: 'programming'
}
]
var values2 = [
{
name: 'cat',
food: 'fish',
age: '12'
},
{
name: 'elephant',
food: 'leafs',
age: '13'
},
{
lastname: 'dog',
food: 'treats',
age: '22'
}
]
// push into this empty object array
var values3 = [];
values1.forEach(eachValue1Obj => {
const keys = Object.keys(eachValue1Obj);
keys.forEach(eachKey => {
values2.forEach(eachValue2Obj => {
if (
eachValue1Obj[eachKey] &&
eachValue2Obj[eachKey] &&
eachValue1Obj[eachKey] === eachValue2Obj[eachKey]
) {
const x = {
key: eachKey,
value: eachValue1Obj[eachKey]
};
values3.push(x)
}
})
})
})
console.log('Values 3 Array ==>', values3);

How can I output multiple results from an array

I have this array of objects, that initially only had name and unit fields. I recently added a unitConv field of array type.
I used to output an array of strings with the name and unit from every object.
const ingredients = [
{name: 'wine', unit: 'ml', unitConv: []},
{name: 'salt', unit: 'gr', unitConv: [{unitMeasure: { name: 'spoon'}}, {unitMeasure: { name: 'tea-spoon'}}]},
{name: 'onion', unit: 'piece', unitConv: []},
]
const response = ingredients.map(ing => `${ing.name} [${ing.unit}]`)
And this is the response:
["wine [ml]", "salt [gr]", "onion [piece]"]
Now that I added unitConv, I want to see if any unitConv are available in the object, and pass those too, as options, like this:
["wine [ml]", "salt [gr]", "onion [piece]", "salt[spoon]", "salt[tea-spoon]"]
And I want to keep the initial value of salt too, the one the uses the 'gr' as a unit. So for salt, because I have one unit and two unitConv, I want to output it three times, with each of this options.
If one of the objects doesn't have unitConv, the unitConv fields will appear as an empty array, like in the example above.
You can use Array#flatMap to create the second array to concatenate with the first.
const ingredients = [
{name: 'wine', unit: 'ml', unitConv: []},
{name: 'salt', unit: 'gr', unitConv: [{unitMeasure: { name: 'spoon'}}, {unitMeasure: { name: 'tea-spoon'}}]},
{name: 'onion', unit: 'piece', unitConv: []},
]
const response = ingredients.map(ing => `${ing.name} [${ing.unit}]`)
.concat(ingredients.flatMap(({name, unitConv})=>
unitConv.map(x => `${name} [${x.unitMeasure.name}]`)));
console.log(response);
a simple array reduce method:
const ingredients =
[ { name: 'wine', unit: 'ml', unitConv: [] }
, { name: 'salt', unit: 'gr', unitConv:
[ { unitMeasure: { name: 'spoon' } }
, { unitMeasure: { name: 'tea-spoon' } }
]
}
, { name: 'onion', unit: 'piece', unitConv: [] }
]
const resp2 = ingredients.reduce((resp,{name,unit,unitConv}) =>
{
resp.push( `${name} [${unit}]` )
unitConv.forEach(({unitMeasure}) =>
resp.push(`${name} [${unitMeasure.name}]`))
return resp
},[])
console.log( resp2 )
.as-console-wrapper{max-height:100% !important;top: 0;}
you can use flatMap and inside its callback function check for unitConv array lentgh, if it's true then you can use a map for that. here is the demo:
const ingredients = [{
name: 'wine',
unit: 'ml',
unitConv: []
},
{
name: 'salt',
unit: 'gr',
unitConv: [{
unitMeasure: {
name: 'spoon'
}
}, {
unitMeasure: {
name: 'tea-spoon'
}
}]
},
{
name: 'onion',
unit: 'piece',
unitConv: []
},
]
function strFormat(name, unit) {
return `${name} [${unit}]`;
}
const result = ingredients.flatMap((ing) => {
if (ing.unitConv.length) {
const ingAllUnits = ing.unitConv.map((unit) => strFormat(ing.name, unit.unitMeasure.name));
ingAllUnits.push(strFormat(ing.name, ing.unit));
return ingAllUnits;
} else return strFormat(ing.name, ing.unit);
});
console.log(result);

Filter two array of objects and get a resultant array

I'm trying to check for condition where carId in one array is equal to id of another array.
Below is the code snippet.
const arr1 = [{
id: '1',
type: 'car',
name: 'BMW',
},
{
id: '2',
type: 'car',
name: 'Audi',
},
{
id: '3',
type: 'car',
name: 'Benz',
}
];
const arr2 = [{
carId: '1'
}, {
carId: '3'
}];
const result = arr2.map(val => arr2.find(val.carId === id))
console.log(result)
The result that I'm expecting is
[{
id: '1',
type: 'car',
name: 'BMW',
},
{
id: '3',
type: 'car',
name: 'Benz',
}
];
Could anyone please help?
While you should use .filter() on arr1, and pass a callback to .find(), I'd probably first convert arr2 to a simple list of IDs and use .includes() instead.
const arr1 = [{
id: '1',
type: 'car',
name: 'BMW',
},
{
id: '2',
type: 'car',
name: 'Audi',
},
{
id: '3',
type: 'car',
name: 'Benz',
}
];
const arr2 = [{
carId: '1'
}, {
carId: '3'
}];
const ids = arr2.map(o => o.carId);
const result = arr1.filter(val => ids.includes(val.id))
console.log(result)
or better yet, convert arr2 to a Set.
const arr1 = [{
id: '1',
type: 'car',
name: 'BMW',
},
{
id: '2',
type: 'car',
name: 'Audi',
},
{
id: '3',
type: 'car',
name: 'Benz',
}
];
const arr2 = [{
carId: '1'
}, {
carId: '3'
}];
const ids = arr2.map(o => o.carId);
const idSet = new Set(ids);
const result = arr1.filter(val => idSet.has(val.id))
console.log(result)
const arr1 = [{
id: '1',
type: 'car',
name: 'BMW',
},
{
id: '2',
type: 'car',
name: 'Audi',
},
{
id: '3',
type: 'car',
name: 'Benz',
}
];
const arr2 = [{
carId: '1'
}, {
carId: '3'
}];
const result = arr1.filter(a1val => arr2.find(a2val => a2val.carId === a1val.id) !== undefined);
console.log(result);
This might work
const result = arr2.map(val => arr1.find(item => item.id === val.carId))

Clone array of object removes class type

I have to deep clone an array of objects
filterList: Filter[] = [
new ChipsFilter('Rating', 'rating',
[
{
name: '5 ★',
key: '5',
value: true
},
{
name: '4 ★',
key: '4',
value: true
},
{
name: '3 ★',
key: '3',
value: true
},
{
name: '2 ★',
key: '2',
value: true
},
{
name: '1 ★',
key: '1',
value: true
}
]),
new CheckboxFilter('Country', 'country', [
{
name: 'India',
key: 'india',
value: true
},
{
name: 'Brazil',
key: 'brazil',
value: false
},
{
name: 'UAE',
key: 'uae',
value: true
},
{
name: 'Sri Lanka',
key: 'sri-lanka',
value: true
},
{
name: 'USA',
key: 'usa',
value: false
},
{
name: 'England',
key: 'england',
value: true
},
{
name: 'South Africa',
key: 'south-africa',
value: true
}
]),
new CalendarFilter('Date', 'createdAt', [
{
name: 'Start Date',
key: 'startDate',
value: ''
},
{
name: 'End Date',
key: 'endDate',
value: ''
}
]),
];
After clone I want the data type of objects to be same but I get the object as the type instead, have tried below methods for cloning.
Using JSON stringify
this.filterList = this.filterList.map(a => Object.assign({}, a));
Using object.assign
this.filterList = this.filterList.map(a => Object.assign({}, a));
The first argument to Object.assign() is the target object. That object effectively is the result. What Object.assign() does is just copy over own enumerable properties of your CalendarFilter instances to that target.
What you could do instead is create new instances of your objects in array.map() instead of assigning them to a generic object with Object.assign().
this.filterList = this.filterList.map(a => new CalendarFilter(...))
Of course, you need to use the right constructor for each type you encounter in your array.
This will take into account the variable Object types:
class ChipsFilter {constructor(){this.chipsProp="chipsProp"}}
class CheckboxFilter {constructor(){this.checkboxProp= "checkboxProp"}}
class CalendarFilter {constructor(){this.calendarProp= "calendarProp"}}
const filterList = [
new ChipsFilter(),
new CheckboxFilter(),
new CalendarFilter(),
];
let out = filterList.map(obj=>Object.assign(new obj.constructor, obj));
console.log(out[0].constructor, out[0]);
console.log(out[1].constructor, out[1]);
console.log(out[2].constructor, out[2]);

Categories