Comparing two arrays with objects with unordered keys - javascript

I know they're several questions that indicate how to do this, however, when the keys of the objects are in a different order the provided solutions do not work.
let array1 = [
{ name: 'David', age: 30 },
{ name: 'Amy', age: 39 }
];
let array2 = [
{ age: 30, name: 'David' },
{ age: 39, name: 'Amy' }
];
Comparing the arrays
console.log(array1.every((value, index) => {
return JSON.stringify(value) === JSON.stringify(array2[index]);
})
// Returns false
// Expected true
Understandably these two arrays are different but the data is the same. So...
How do I compare arrays with objects in which I cannot guarantee that the keys are ordered identically?

You can do a proper object comparison, there are a lot of ways to do that.
Here's one of the examples:
let array1 = [
{ name: 'David', age: 30 },
{ name: 'Amy', age: 39 }
];
let array2 = [
{ age: 30, name: 'David' },
{ age: 39, name: 'Amy' }
];
console.log(array1.every((value, index) =>
Object.keys(value).length === Object.keys(array2[index]).length &&
JSON.stringify(value) === JSON.stringify({...value, ...array2[index]})
));

1) Convert array of objects to array of strings
2) Compare both array of strings (one way is to do with reduce as below).
let array1 = [
{ name: "David", age: 30 },
{ name: "Amy", age: 39 }
];
let array2 = [
{ age: 30, name: "David" },
{ age: 39, name: "Amy" }
];
const isEqual = (arr1, arr2) => {
if (arr1.length !== arr2.length) {
return false;
}
const toStr = ({ name, age }) => `${name}-${age}`;
const a1 = Array.from(arr1, toStr);
const a2 = Array.from(arr2, toStr);
return a1.every(item => a2.includes(item));
};
console.log(isEqual(array1, array2));

Related

search for a specific property in array of objects and return boolean

lets say i have an array of objects
let arr = [
{
name: "john",
age: 22
},
{
name: "george",
age: 55
}
];
and an object
let obj = {
name: "bill",
age: 55
}
and i want to search all arr objects to find anyone with the same age as obj.age and return a boolean depending whether it includes a same property or not.
i can obviously do :
let find = arr.filter(i => i.age === obj.age);
let bool = find.length > 0 && true;
but is there a way to call a method (lodash,plain js or whatever) to just get this by design like method(arr,obj.age) //returns true ?
let arr = [
{
name: "john",
age: 22
},
{
name: "george",
age: 55
}
];
let obj = {
name: "bill",
age: 55
}
let find = arr.filter(i => i.age === obj.age);
let bool = find.length > 0 && true;
console.log(bool)
You can use some. So basically it will return a boolean value if any of the object property in array matches the required value
let arr = [{
name: "john",
age: 22
},
{
name: "george",
age: 55
}
];
let obj = {
name: "bill",
age: 55
}
const val = arr.some(item => item.age === obj.age);
console.log(val)
we can do it in two ways. we can use the some function and get the boolean directly or by find function, we can convert it to a boolean using !! operator.
let arr = [{
name: "john",
age: 22
},
{
name: "george",
age: 55
}
];
let obj = {
name: "bill",
age: 55
}
const val1 = arr.some(item => item.age === obj.age);
console.log(val1)
const val2 = !!arr.find(item => item.age === obj.age);
console.log(val2)

Comparing two arrays of objects and return final result

I have two array of objects (array1, array2). I am trying return final array(as shown below) which eliminates duplicates from array2 but not array1. I am giving priority to array1.
array1 =[
{ phone: "07485454", name: "John" },
{ phone: "054554", name: "Ryan" },
]
array2 =[
{ phone: "2144564", name: "John" },
{ phone: "286456", name: "Mike" },
]
This is something I want as a final result. Remove duplicates from array2 only.
Final Array:
[
{ phone: "07485454", name: "John" },
{ phone: "054554", name: "Ryan" },
{ phone: "286456", name: "Mike" },
]
This is something that I have tried:
for(let i = 0; i < array1.length; i++) {
let name = array1[i].name;
for(let a = 0; i < array2.length; a++) {
let newname = array2[a].name;
if(name !== newname) {
array1.push(
{
phone: array2[a].phone,
name: array2[a].name
});
}
console.log(array1);
}
}
This is the error I get.
"errorType": "TypeError",
"errorMessage": "Cannot read property 'name' of undefined",
You were close to the solution, you can create a Set to contain names of your array1 elements and pushing array1 elements to your result array; subsequently add elements of array2 which names are not contained in your set to your result array :
function removeDuplicates(array1, array2) {
const result = [];
const set = new Set();
for (const elem of array1) {
result.push(elem);
set.add(elem.name);
}
for (const elem of array2) {
if (!set.has(elem.name)) {
result.push(elem);
}
}
return result;
}
const array1 =[
{ phone: "07485454", name: "John" },
{ phone: "054554", name: "Ryan" }
];
const array2 =[
{ phone: "2144564", name: "John" },
{ phone: "286456", name: "Mike" }
];
console.log(JSON.stringify(removeDuplicates(array1, array2)));
you have done a typo mistake in inner for loop condition a < array2.length
Changing the array1 length will results to infinite loop
Every time, when the if(name !== newname) the condition is true, inserting a new object in array1 will results to changing the array1 length.
let array1 =[
{ phone: "07485454", name: "John" },
{ phone: "054554", name: "Ryan" },
]
let array2 =[
{ phone: "2144564", name: "John" },
{ phone: "286456", name: "Mike" },
]
let result = array2.reduce((accumulator, currentItem) =>{
let index = accumulator.findIndex(item => item.name === currentItem.name);
if(index === -1){
accumulator.push(currentItem);
}
return accumulator;
},array1);
console.log(result);

How do I loop through an array (recurision) and push object key/value pairs in another array?

Given an array. I want to create a function recursive that loops through arr and pushes the key/value pairs in a new array (arr2) like this:
var arr2 = []
function recursive(arr) // function gets executed
arr2 //will return the array with arrays
[
[ mike, 22]
[ robert, 12]
[ roger, 44]
[ peter, 28]
[ ralph, 67]
]
I so far have this code but it pushes the objects into arr2, not arrays!
var arr =[{name:'mike', age:22},{name:'robert', age:12},{name:'roger', age:44},{name:'peter', age:28},{name:'Ralph', age:67}]
var arr2 = []
function recursive(arr) {
if (Array.isArray(arr)) {
arr.forEach(function(object) {
arr2.push(object)
})
}
}
recursive(arr)
console.log(arr2)
How can I tackle that?
PS: since I am a beginner, please stick to my code approach as much as possible. I am sure there are way better ways to do that.
You can simply map like that:
var arr2 = arr.map(x=>[x.name, x.age]);
You could map the values of the objects. This works for object with a wanted order
function getValues(array) {
return array.map(Object.values);
}
var array = [{ name: 'mike', age: 22 }, { name: 'robert', age: 12 }, { name: 'roger', age: 44 }, { name: 'peter', age: 28 }, { name: 'Ralph', age: 67 }]
console.log(getValues(array));
.as-console-wrapper { max-height: 100% !important; top: 0; }
If not, you could map with a given keys array.
You could map the values of the objects. This works for object with a wanted order
function getValues(array) {
var keys = ['name', 'age']
return array.map(o => keys.map(k => o[k]));
}
var array = [{ name: 'mike', age: 22 }, { name: 'robert', age: 12 }, { name: 'roger', age: 44 }, { name: 'peter', age: 28 }, { name: 'Ralph', age: 67 }]
console.log(getValues(array));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Get values from an array of objects

I am looping through my array to get the corresponding field value:
var someFun = function (nm) {
var names = [{name: 'joe', age: 'nine'}, {name: 'tom', age: 'ten'}];
for (var i=0; i < names.length; i++) {
if (names[i].name === nm) return names[i].age;
}
};
var username = 'tom';
var printme = someFun(username);
console.log('hey: ', printme)
How can I do the same using Object.keys(), or map, or forEach? Much cleaner and ES6 compliant.
Simply use find
([{name: 'joe', age: 'nine'}, {name: 'tom', age: 'ten'}].find( (s)=> s.name=="tom" )||{}).age //10
([{name: 'joe', age: 'nine'}, {name: 'tom', age: 'ten'}].find( (s)=> s.name=="tom2" )||{}).age //undefined
Demo
var names = [{
name: 'joe',
age: 'nine'
}, {
name: 'tom',
age: 'ten'
}];
function getAge(names, name) {
return (names.find((s) => s.name == name) || {}).age;
}
console.log(getAge(names, "tom"))
console.log(getAge(names, "tom2"))
You can use array.prototype.find:
var names = [{name: 'joe', age: 'nine'}, {name: 'tom', age: 'ten'}];
var someFun = (nm) => {
var found = names.find(el => el.name === nm);
return found && found.age || null;
}
console.log(someFun('tom'));
From Array.prototype.find()
The find() method returns the value of the first element in the array
that satisfies the provided testing function.
If there are multiples objects with the same name?
With Array.prototype.filter()
var names = [{
name: 'joe',
age: 9
},
{
name: 'tom',
age: 10
},
{
name: 'frank',
age: 9
},
{
name: 'joe',
age: 15
}
];
function getData(arr, search) {
// Filter array of objects by a search pair
return arr.filter(o => o[search[0]] === search[1]);
}
function listBy(arr, k) {
// Output values from an array of objects by a key as a comma separated string
return arr.map(o => o[k]).join(",");
}
console.log(getData(names, ["name", "joe"]));
console.log(listBy(getData(names, ["name", "tom"]), "age"));
console.log(listBy(getData(names, ["age", 9]), "name"));
IE doesn't support find, check the Browser compatibility. Maybe you don't need to support IE, but it's still a gets 3.74% of global usage as of Oct 2017. However, it does support filter.
DEMO
var users = [
{ name: "Bill", age: 'nine' },
{ name: 'Tedd', age: 'ten' }
];
function getAgeFromUsers(name) {
const arr = users.filter(u => u.name === name);
return !!arr.length ? arr[0].age : "That user ain't here";
}
console.log(getAgeFromUsers('Tedd'));
console.log(getAgeFromUsers("Lion 'O"));
var someFun = nm => {
const names = [{name: 'joe', age: 'nine'}, {name: 'tom', age: 'ten'}];
const foundName = names.find(name => name.name === nm)
return foundName ? foundName.age : null
};
This replicates what you have above. Although i would personally return the object then age the age from that instead of just returning the age.

Merge property from an array of objects into another based on property value lodash

I have 2 arrays of objects, they each have an id in common. I need a property from objects of array 2 added to objects array 1, if they have matching ids.
Array 1:
[
{
id: 1,
name: tom,
age: 24
},
{
id: 2,
name: tim,
age: 25
},
{
id: 3,
name: jack,
age: 24
},
]
Array 2:
[
{
id: 1,
gender: male,
eyeColour: blue,
weight: 150
},
{
id: 2,
gender: male,
eyeColour: green,
weight: 175
},
{
id: 3,
gender: male,
eyeColour: hazel,
weight: 200
},
]
Desired Outcome:
[
{
id: 1,
name: tom,
age: 24,
eyeColour: blue,
},
{
id: 2,
name: tim,
age: 25,
eyeColour: green,
},
{
id: 3,
name: jack,
age: 24,
eyeColour: hazel,
},
]
I tried using lodash _.merge function but then I end up with all properties into one array, when I only want eyeColour added.
Lodash remains a highly useful bag of utilities, but with the advent of ES6 some of its use cases are less compelling.
For each object (person) in the first array, find the object in the second array with matching ID (see function findPerson). Then merge the two.
function update(array1, array2) {
var findPerson = id => array2.find(person => person.id === id);
array1.forEach(person => Object.assign(person, findPerson(person.id));
}
For non-ES6 environments, rewrite arrow functions using traditional syntax. If Array#find is not available, write your own or use some equivalent. For Object.assign, if you prefer use your own equivalent such as _.extend.
This will merge all properties from array2 into array1. To only merge eyeColour:
function update(array1, array2) {
var findPerson = id => array2.find(person => person.id === id);
array1.forEach(person => {
var person2 = findPerson(person.id));
var {eyeColour} = person2;
Object.assign(person, {eyeColour});
});
}
Just noticed Paul answered while I was working on my answer but I'll add my very similar code anyway:
var getEyeColour = function (el) { return _.pick(el, 'eyeColour'); }
var out = _.merge(arr1, _.map(arr2, getEyeColour));
DEMO
You can use pick to get only the properties you want before merging:
var result = _.merge( arr1, _.map( arr2, function( obj ) {
return _.pick( obj, 'id', 'eyeColour' );
}));
A solution in plain Javascript
This is a more generic solution for merging two arrays which have different properties to union in one object with a common key and some properties to add.
var array1 = [{ id: 1, name: 'tom', age: 24 }, { id: 2, name: 'tim', age: 25 }, { id: 3, name: 'jack', age: 24 }, ],
array2 = [{ id: 1, gender: 'male', eyeColour: 'blue', weight: 150 }, { id: 2, gender: 'male', eyeColour: 'green', weight: 175 }, { id: 3, gender: 'male', eyeColour: 'hazel', weight: 200 }, ];
function merge(a, b, id, keys) {
var array = [], object = {};
function m(c) {
if (!object[c[id]]) {
object[c[id]] = {};
object[c[id]][id] = c[id];
array.push(object[c[id]]);
}
keys.forEach(function (k) {
if (k in c) {
object[c[id]][k] = c[k];
}
});
}
a.forEach(m);
b.forEach(m);
return array;
}
document.write('<pre>' + JSON.stringify(merge(array1, array2, 'id', ['name', 'age', 'eyeColour']), 0, 4) + '</pre>');
I was looking for the same, but I want to match Id before merging
And in my case, second array may have different number of items, finally I came with this:
var out = arr1.map(x => {
return { ...x, eyeColour: arr2.find(y => x.id === y.id)?.eyeColour }
});

Categories