Compare 2 arrays and assign matching value [duplicate] - javascript

This question already has answers here:
Merge property from an array of objects into another based on property value lodash
(5 answers)
Closed 4 years ago.
I have 2 array of objects
The first one called data:
const data = [
{
id: 1,
nombre: 'Piero',
},
{
id: 4,
nombre: 'Nelson',
},
{
id: 7,
nombre: 'Diego'
},
]
and the second called subs:
const subs = [
{
id: 1,
name: 'Temprano',
},
{
id: 4,
name: 'A tiempo',
},
{
id: 7,
name: 'Tarde'
},
]
In which I want to compare that if they have the same ID, the subs array will pass its name value to it and if it does not match that it puts a '-' in the data array, try this way:
data.forEach((d)=>{
subs.forEach((s)=>{
if(d.id === s.id){
d.subname = s.name;
}
else {
d.subname = '-';
}
});
});
But always assign the values with '-' as if it does not match any. What part am I doing wrong? Is there any other simpler way to do this? I would greatly appreciate your help.
The size of the subs array may vary.

It looks like you are not exiting the inner loop when a successful match is found.
In the first example where you are looking for a match for Piero, in your first iteration 1===1 and d.subname is correctly set to 'Temprano'. However, you then continue to compare the values- 1 !== 4 so Temprano is overwritten with '-', and 1 !== 7 so it is overwritten again.
An alternate approach:
data.forEach(d => {
const match = subs.find(s => s.id === d.id);
d.subname = match ? match.name : '-';});
I'd also recommend adding a case where you're not expecting to find a match, so you can see that it works in both cases!

https://codepen.io/anon/pen/MGGBLP?editors=0010
const data = [
{
id: 1,
nombre: 'Piero',
},
{
id: 4,
nombre: 'Nelson',
},
{
id: 7,
nombre: 'Diego'
},
];
const subs = [
{
id: 1,
name: 'Temprano',
},
{
id: 4,
name: 'A tiempo',
},
{
id: 7,
name: 'Tarde'
},
];
// by caching one of the arrays in an object, it reduces the run time to linear.
const obj = subs.reduce((acc, item) => {
acc[item.id] = item;
return acc;
})
data.forEach(d => {
if (d.id in obj) {
d.subname = obj[d.id].name;
} else {
d.subname = '-';
}
});
console.log(data);

You just need two lines for this:
var findIds = id => subs.find(findId => findId.id === id);
data.forEach(findId => Object.assign(findId, findIds(findId.id)));
Your data array object should now include the name property from it's respective id sharing object in subs array.
jsFiddle: https://jsfiddle.net/AndrewL64/9k1d3oj2/1/

Related

Loop through two arrays and check if key value in items of the first array are present in the second [JavaScript] [duplicate]

This question already has answers here:
How to get the difference between two arrays in JavaScript?
(84 answers)
Closed last month.
This post was edited and submitted for review last month and failed to reopen the post:
Original close reason(s) were not resolved
I am trying to loop a array of objects and compare it with another array and check of the key value is present in the array which is to be compared. Here I am not going to check for the array length too.
Example
Array1 is the array which needs to be compared to array 2
[{name:'Linus',id:1},{name:'Anthony',id:2},{name:'Carl',id:3}]
Array 2
[{name:'Linus',id:1},{name:'Anthony',id:2},{name:'Beth',id:3},{name:'Kyle',id:4}]
I am trying to validate if all the id values in array 1 are present in array 2 and if not present then I expect a boolean value and get the best solution in terms of performance.
array1.every(item1 => array2.some(item2 => item1.id === item2.id))
Pretty easy using the .findIndex() in a loop and filter depending upon your needs.
const array1 = [{
name: 'Linus',
id: 1
}, {
name: 'Anthony',
id: 2
}, {
name: 'Carl',
id: 3
}];
const array2 = [{
name: 'Linus',
id: 1
}, {
name: 'Anthony',
id: 2
}, {
name: 'Beth',
id: 3
}, {
name: 'Kyle',
id: 4
}];
array1.forEach((a1) => {
const idx = array2.findIndex((x) => {
return x.id === a1.id
});
console.log(idx);
});
// idx set to -1 if it is not found
array2.forEach((a2) => {
const idx = array1.findIndex((x) => {
return x.id === a2.id
});
console.log(idx);
});
let matches = array2.filter((a) => {
return array1.findIndex((x) => {
return x.id === a.id
}) > -1;
});
console.log(matches);
let nomatches = array2.filter((a) => {
return array1.findIndex((x) => {
return x.id === a.id
}) == -1;
});
console.log(nomatches);
const arr1 = [{
name: 'Linus',
id: 1
}, {
name: 'Anthony',
id: 2
}, {
name: 'Carl',
id: 3
}];
const arr2 = [{
name: 'Linus',
id: 1
}, {
name: 'Anthony',
id: 2
}, {
name: 'Beth',
id: 3
}, {
name: 'Kyle',
id: 4
}]
let compareTwoArrayOfObjects = (
first_array_of_objects,
second_array_of_objects
) => {
return (
first_array_of_objects.length === second_array_of_objects.length &&
first_array_of_objects.every((element_1) =>
second_array_of_objects.some(
(element_2) =>
element_1.id === element_2.id
)
)
);
};
console.log(compareTwoArrayOfObjects(arr1, arr2));
You can do it with this method to compare each object's element and check their id value

How to access object property by variable in Javascript [duplicate]

This question already has answers here:
Accessing an object property with a dynamically-computed name
(19 answers)
Closed 3 years ago.
I have an object like
let arr = [
{
title: "hello",
pivot: {
id: 1,
bid: 3
}
},
{
title: "home",
pivot: {
id: 2,
bid: 3
}
},
{
title: "nice",
pivot: {
id: 3,
bid: 3
}
}
];
I want to access its property dynamically. I want to access id property's value from pivot from first object of this array. And it's should be dynamic.
This is what I tried already.
let s = "0.pivot.id"
let res = arr[s]
console.log(res)
I can access by arr[0].pivot.id but this is not my case. I want it dynamically.
You can split the string and loop through it updating a variable refrencing the last found value :
let arr = [
{
title: "hello",
pivot: {
id: 1,
bid: 3
}
},
{
title: "home",
pivot: {
id: 2,
bid: 3
}
},
{
title: "nice",
pivot: {
id: 3,
bid: 3
}
}
];
let s = "0.pivot.id";
const getValue = (arr, str) => {
let ref = arr;
const keys = str.split(".");
keys.forEach(k => {
ref = ref[k];
});
return ref;
};
const result = getValue(arr, s);
console.log(result);
what you tried would give you a property which key was 0.pivot.id. So it might work if your object looks like this
{
'0.pivot.id': 'something'
}
There is no native way to access deeper level of an object dynamically. You would need to use recursion for that.
It's quite easy though, You could simply split your key into an array of keys and then recursively check your array for matching keys.
let arr = [
{
title: "hello",
pivot: {
id: 1,
bid: 3
}
},
{
title: "home",
pivot: {
id: 2,
bid: 3
}
},
{
title: "nice",
pivot: {
id: 3,
bid: 3
}
}
];
function getDynamicKeyRecursively(object, key) {
// the key needs to be an array,
// if it isn't, we split it into an array
if(typeof key === 'string') {
key = key.split('.');
}
// we get the current value of the current object
let currentValue = object[key[0]];
// remove the first index of the key
key.shift()
// if the current value is an object or an array, we recursively check this value for what we want
// otherwise, we return the value.
return Array.isArray(currentValue) || typeof currentValue === 'object' ? getDynamicKeyRecursively(currentValue, key) : currentValue;
}
console.log(getDynamicKeyRecursively(arr, '1.pivot.id'));

How to add a value to an array in a specific location with JS

I have an array of objects:
const array = [
{ id: 1 },
{ id: 2 },
{ id: 3 },
{ id: 4 }
];
and I need to add another entry to it, but it needs to be placeable within any location in the array. So for example:
array.push({ id: 5, after_id: 2 }); and this should place the new entry between ids 2 and 3. Is there some standard way of doing this?
#p.s.w.g Has posted what is probably the best solution in a comment already, but I thought I'd post my original solution here as an answer now this is reopened.
You can use some to iterate through the array until the correct index is found, then you can slice the array and insert the item at the relevant index:
const arrayTest = [{
id: 1
},
{
id: 2
},
{
id: 3
},
{
id: 4
}
];
const insertAfterId = (array, item, idAfter) => {
let index = 0;
array.some((item, i) => {
index = i + 1;
return item.id === idAfter
})
return [
...array.slice(0, index),
item,
...array.slice(index, array.length),
];
};
const result = insertAfterId(arrayTest, {
id: 6
}, 2)
console.dir(result)

Remove last added value from array without mutating it

dontMutateMeArray=[1,2,3,3,3,4,5];
toBeRemoved=3;
newArray=dontMutateMeArray.something(toBeRemoved); // [1,2,3,3,4,5]
iDontWantArray=dontMutateMeArray.filter(value=>value===toBeRemoved); // [1,2,4,5]
I indeed need it for array of objects too. And I specifically need to remove the last added object (ie. the one with higher index in the array). Something like:
dontMutateMeArray=[{id:1},{id:2},{id:3,sth:1},{id:3,sth:42},{id:3,sth:5},{id:4},{id:5}];
toBeRemoved=3;
newArray=dontMutateMeArray.something(toBeRemoved); // [{id:1},{id:2},{id:3,sth:1},{id:3,sth:42},{id:4},{id:5}]
iDontWantArray=dontMutateMeArray.filter(obj=>obj.id===toBeRemoved); // [{id:1},{id:2},{id:4},{id:5}]
iDontWantArray2=dontMutateMeArray.blahBlah(toBeRemoved); // [{id:1},{id:2},{id:3,sth:1},{id:3,sth:5},{id:4},{id:5}]
You could iterate from right and check with a closure.
var dontMutateMeArray = [{ id: 1 }, { id: 2 }, { id: 3, sth: 1 }, { id: 3, sth: 42 }, { id: 3, sth: 5 }, { id: 4 }, { id: 5 }],
toBeRemoved = 3,
newArray = dontMutateMeArray.reduceRight((found => (r, a) => (!found && a.id === toBeRemoved ? found = true : r.unshift(a), r))(false), []);
console.log(newArray);

How can I get a unique array based on object property using underscore

I have an array of objects and I want to get a new array from it that is unique based only on a single property, is there a simple way to achieve this?
Eg.
[ { id: 1, name: 'bob' }, { id: 1, name: 'bill' }, { id: 1, name: 'bill' } ]
Would result in 2 objects with name = bill removed once.
Use the uniq function
var destArray = _.uniq(sourceArray, function(x){
return x.name;
});
or single-line version
var destArray = _.uniq(sourceArray, x => x.name);
From the docs:
Produces a duplicate-free version of the array, using === to test object equality. If you know in advance that the array is sorted, passing true for isSorted will run a much faster algorithm. If you want to compute unique items based on a transformation, pass an iterator function.
In the above example, the function uses the objects name in order to determine uniqueness.
If you prefer to do things yourself without Lodash, and without getting verbose, try this uniq filter with optional uniq by property:
const uniqFilterAccordingToProp = function (prop) {
if (prop)
return (ele, i, arr) => arr.map(ele => ele[prop]).indexOf(ele[prop]) === i
else
return (ele, i, arr) => arr.indexOf(ele) === i
}
Then, use it like this:
const obj = [ { id: 1, name: 'bob' }, { id: 1, name: 'bill' }, { id: 1, name: 'bill' } ]
obj.filter(uniqFilterAccordingToProp('abc'))
Or for plain arrays, just omit the parameter, while remembering to invoke:
[1,1,2].filter(uniqFilterAccordingToProp())
If you want to check all the properties then
lodash 4 comes with _.uniqWith(sourceArray, _.isEqual)
A better and quick approach
var table = [
{
a:1,
b:2
},
{
a:2,
b:3
},
{
a:1,
b:4
}
];
let result = [...new Set(table.map(item => item.a))];
document.write(JSON.stringify(result));
Found here
You can use the _.uniqBy function
var array = [ { id: 1, name: 'bob' }, { id: 2, name: 'bill' }, { id: 1, name: 'bill' },{ id: 2, name: 'bill' } ];
var filteredArray = _.uniqBy(array,function(x){ return x.id && x.name;});
console.log(filteredArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js"></script>
In the above example, filtering is based on the uniqueness of combination of properties id & name.
if you have multiple properties for an object.
then to find unique array of objects based on specific properties, you could follow this method of combining properties inside _.uniqBy() method.
I was looking for a solution which didn't require a library, and put this together, so I thought I'd add it here. It may not be ideal, or working in all situations, but it's doing what I require, so could potentially help someone else:
const uniqueBy = (items, reducer, dupeCheck = [], currentResults = []) => {
if (!items || items.length === 0) return currentResults;
const thisValue = reducer(items[0]);
const resultsToPass = dupeCheck.indexOf(thisValue) === -1 ?
[...currentResults, items[0]] : currentResults;
return uniqueBy(
items.slice(1),
reducer,
[...dupeCheck, thisValue],
resultsToPass,
);
}
const testData = [
{text: 'hello', image: 'yes'},
{text: 'he'},
{text: 'hello'},
{text: 'hell'},
{text: 'hello'},
{text: 'hellop'},
];
const results = uniqueBy(
testData,
item => {
return item.text
},
)
console.dir(results)
In case you need pure JavaScript solution:
var uniqueProperties = {};
var notUniqueArray = [ { id: 1, name: 'bob' }, { id: 1, name: 'bill' }, { id: 1, name: 'bill' } ];
for(var object in notUniqueArray){
uniqueProperties[notUniqueArray[object]['name']] = notUniqueArray[object]['id'];
}
var uniqiueArray = [];
for(var uniqueName in uniqueProperties){
uniqiueArray.push(
{id:uniqueProperties[uniqueName],name:uniqueName});
}
//uniqiueArray
unique array by id property with ES6:
arr.filter((a, i) => arr.findIndex(b => b.id === a.id) === i); // unique by id
replace b.id === a.id with the relevant comparison for your case

Categories

Resources