Compare Array of Objects
function compare (arr1, arr2){
//if object key value pair from arr2 exists in arr1 return modified array
for (let obj of arr2) {
if(obj.key === arr1.key){
return obj
}
}
}
// Should return [{key: 1, name : "Bob", {key: 2, name : "Bill"}]
compare([{key: 1}, {key: 2}],
[{key: 1, name : "Bob"}, {key: 3, name : "Joe"}, {key: 2, name : "Bill"}])
I am having a disconnect with looping arrays of objects with different lengths and properties. I have tried looping and IndexOf but due to different lengths, I cannot compare the two arrays that way. I feel like a filter might be a good tool but have had no luck. Any thoughts?
Create a Set of properties from the 1st array (the keys), and then Array#filter the 2nd array (the values) using the set:
function compareBy(prop, keys, values) {
const propsSet = new Set(keys.map((o) => o[prop]));
return values.filter((o) => propsSet.has(o[prop]));
}
const result = compareBy('key', [{key: 1}, {key: 2}],
[{key: 1, name : "Bob"}, {key: 3, name : "Joe"}, {key: 2, name : "Bill"}])
console.log(result);
Related
I need to know if an array of objects contains at least two same objects in it, in JavaScript.
I have a form that allow people to create questions (title, description, type, answer options). I need to check whether the user has entered multiple answer options with the same label. They are stored in an array.
// The array of answer options
let array = [{value: 'a'}, {value: 'b'}, {value: 'c'}, {value: 'a'}]
I tried using array.indexOf({value: 'a'}) and array.lastIndexOf({value: 'a'}) but they both give me an index of -1.
Separate objects are never === to each other, so you'll have to use a different method. One option is to create a Set of the stringified objects, and return true once any duplicate string is found:
const hasDupes = (arr) => {
const strings = new Set();
for (const obj of arr) {
const string = JSON.stringify(obj);
if (strings.has(string)) {
return true;
}
strings.add(string);
}
return false;
};
console.log(hasDupes([{value: 'a'}, {value: 'b'}, {value: 'c'}, {value: 'a'}]));
console.log(hasDupes([{value: 'a'}, {value: 'b'}, {value: 'c'}]));
If you are only concerned about the value property and you use case is not more complex and you can simply do this in one line via:
let hasDupes = arr => new Set(arr.map(x => x.value)).size !== arr.length
console.log(hasDupes([{value: 'a'}, {value: 'b'}, {value: 'c'},{value: 'a'}]))
console.log(hasDupes([{value: 'a'}, {value: 'b'}, {value: 'c'}]))
You would use Set to add the values of value and if the size of it is smaller than the actual input array length than you had duplicates. There is no need to do JSON.stringify, compare strings etc if you only care about that one property being checked.
Also JSON.stringify has issues when comparing equality of objects.
Use findIndex:
let array = [{value: 'a'}, {value: 'b'}, {value: 'c'}, {value: 'a'}];
const index = array.findIndex(({ value }) => value == "a");
console.log(index);
indexOf will return the instance of an object
{value: 'a'} !== {value: 'a'};
as they are both different instances of objects.
You can find the object
const obj = array.find(item => item.value === 'a')
You can use lodash.js to compare two objects.
Please see the sample below.
let array = [{ value: "a" }, { value: "b" }, { value: "c" }, { value: "a" }];
const object = { value: "a" };
countObjOccurrences = object => {
let occurances = 0;
array.map(item => {
if (_.isEqual(item, object)) {
occurances += 1;
}
});
return occurances;
};
This function will return 2.
This question already has answers here:
Filter array of objects based on another array in javascript
(10 answers)
Closed 3 years ago.
I want to remove all the object from a data array that contains the same id in an array of id. How can I achieve this task without looping it?
const id = [1, 2];
const data = [
{id: 1},
{id: 2},
{id: 3}
];
console.log(data);
You can try with Array.prototype.filter()
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
and Array.prototype.includes():
The includes() method determines whether an array includes a certain value among its entries, returning true or false as appropriate.
const id = [1, 2];
const data = [
{id: 1},
{id: 2},
{id: 3}
];
var res = data.filter(i => !id.includes(i.id));
console.log(res);
let newData = data.filter(item => !id.includes(item.id));
console.log(newData);
You can use .filter() and .includes() for filtering your object.
const id = [1, 2];
let data = [
{id: 1},
{id: 2},
{id: 3}
];
data = data.filter((item) => (!id.includes(item.id)));
console.log(data);
You can use method uniqBy from lodash https://lodash.com/docs/4.17.11#uniqBy
const uniqArray = _.uniqBy([{ 'id': 1 }, { 'id': 2 }, { 'id': 1 }], 'id');
console.log(uniqArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
I have an array of values, for example:
let values = [1, 2, 3, 4, 5];
And I have another array, containing objects, for example:
let objects = [{name: 'Dennis', value: 2}, {name: 'Charlie', value: 4}];
I would like to produce an array that only contains values that aren't present in the value property of my objects.
So from the examples above, I would return an array of [1, 3, 5]
What I've got at the moment is:
let missingValues = [];
for (let i = 0; i < values.length; i++) {
if (!objects.filter(obj => obj.value === values[i]) {
missingValues.push(values[i]);
}
}
This works, but feels slightly messy, is there a more efficient way to do this?
You could filter the values with a look up in the objects array.
var values = [1, 2, 3, 4, 5],
objects = [{ name: 'Dennis', value: 2 }, { name: 'Charlie', value: 4 }],
result = values.filter(v => !objects.find(({ value }) => value === v));
console.log(result);
...is there a more efficient way to do this?
I assume you really mean "efficient" (as opposed to "concise").
Yes, you can build an object or Set containing the values from the second array, and then use that to filter instead:
let values = [1, 2, 3, 4, 5];
let objects = [{name: 'Dennis', value: 2}, {name: 'Charlie', value: 4}];
let valueSet = new Set();
for (const obj of objects) {
valueSet.add(obj.value);
}
let missingValues = values.filter(value => !valueSet.has(value));
console.log(missingValues);
(You can also use an object for the same thing, if you prefer. let valueSet = Object.create(null); then valueSet[value] = true and !valueSet[value].)
This is only worth doing if the product of the arrays is quite large (hundreds of thousands of entries) or you're doing this a lot.
I want to make a new array by adding an element to an existing array by "push()" method.
This is the existing array:
let arr = [{label: 1, value: 1}, {label: 2, value: 2}];
This is the element I want to add to the existing array:
{label: 3, value: 3}
So this is the full code with "push()" method:
let arr = [{label: 1, value: 1}, {label: 2, value: 2}];
let newArr = arr.push({label: 3, value: 3});
console.log(newArr); // 3
But push() method returns the length of the new array which is "3" to "newArr" variable. However, what I really want is the actual new array instead of its length for "newArr" variable.
Are there any ways to get the actual new array for "newArr" variable?
With push you are actually mutating the original array. Immutable array extending is only available in ES2015+ (supported by all current, major browsers). You can use the spread operator ...:
const original = [1, 2];
const next = [...original, 3];
console.log(next); // [1, 2, 3]
Also new is a reserved keyword and can't be used as an identifier.
First of all, the new keyword has a specified role in javascript, you can't use it as a variable name.
Reserved keywords in javascript.
Secondly, push method works in situ, you don't have to assign it to a new variable. It won't return a new array, but modify the original one.
var arr = [{label: 1, value: 1}, {label:2, value:2}];
arr.push({label:3, value:3});
console.log(arr);
user7334203,
you wrote that arr.push({label:3, value:3}) mean that your new object push in your array so simply print your array so you got your array.
ex
var a = [{label: 1, value: 1}, {label:2, value:2}],
a.push({label:3, value:3}),
var new = a;
console.log(new)
Don't use const .simply do with arr#push .its enough to add with array
var arr= [{label: 1, value: 1}, {label:2, value:2}]
arr.push({label:3, value:3})
console.log(arr)
A good reference for leaning JS is MDN. If you look at the Array#push spec, you'll see that it mutates the input array, returning the new length of the array.
From the MDN documentation push returns the new length of your array, neither the new array, nor the added value.
The push function alters the array in place, meaning it will change the original array (you don't actually need to re-assign it)!
You could have the result you were expecting though by altering your code to:
arr.push({label:3, value:3});
then assign to a new array like:
const newArr = arr;
You can use "concat()" method to get the actual new array for "newArr" variable like below:
let arr = [{label: 1, value: 1}, {label: 2, value: 2}];
let newArr = arr.concat({label: 3, value: 3});
console.log(newArr);
// [
// {label: 1, value: 1},
// {label: 2, value: 2},
// {label: 3, value: 3}
// ]
This code doesn't need "newArr" variable. The actual new array is assigned to the original variable "arr":
let arr = [{label: 1, value: 1}, {label: 2, value: 2}];
arr = arr.concat({label: 3, value: 3});
console.log(arr);
// [
// {label: 1, value: 1},
// {label: 2, value: 2},
// {label: 3, value: 3}
// ]
I'm trying to find a concise way to partition an array of objects into groups of arrays based on a predicate.
var arr = [
{id: 1, val: 'a'},
{id: 1, val: 'b'},
{id: 2, val: 'c'},
{id: 3, val: 'a'}
];
//transform to below
var partitionedById = [
[{id: 1, val: 'a'}, {id: 1, val:'b'}],
[{id: 2, val: 'c'}],
[{id: 3, val: 'a'}
];
I see this question , which gives a good overview using plain JS, but I'm wondering if there's a more concise way to do this using lodash? I see the partition function but it only splits the arrays into 2 groups (need it to be 'n' number of partitions). The groupBy groups it into an object by keys, I'm looking for the same but in an array (without keys).
Is there a simpler way to maybe nest a couple lodash functions to achieve this?
You can first group by id, which will yield an object where the keys are the different values of id and the values are an array of all array items with that id, which is basically what you want (use _.values() to get just the value arrays):
// "regular" version
var partitionedById = _.values(_.groupBy(arr, 'id'));
// chained version
var partitionedById = _(arr).groupBy('id').values().value();