Reputation: 3258
How can I check for the existence of an object in an array in javascript?
Here is a simple example. Let's say I have an array that looks like this:
let array = [{"zone": "WV", "zip": "56855"},
{"zone": "SC", "zip": "28031"},
{"zone": "TN", "zip": "84755"}]
And now I want to add an object to my array
but only if it doesn't already exist.
For example attempting to add this object would fail:
let addMe = [{"zone": "SC", "zip": "28031"}, {"zone": "TN", "zip": "84755"}]
But this would succeed
[{"zone": "SC", "zip": "55555"}, {"zone": "TN", "zip": "88888"}]
Obviously addMe
is an array that would need to be stepped thru, failing on some objects, succeeding on others.
I am trying to use filter
but its not working like I want. And I'm having to step thru the original array as well as step thru the object I'm trying to add, creating nested for loops which is confusing as hell. This is my attempt:
array.filter(function(item){
addMe.forEach(function(element){
if(item.zone != element.zone && zone.zip!= element.zip){
array.push(element);
}
});
});
Is there a better way?
Upvotes: 1
Views: 126
Reputation: 1009
Alternatively you can compare all values of two objects with JSON.stringify.
So we first filter
to not have any duplicate, by using some
within which we compare the stringified objects.
let array = [{"zone": "WV", "zip": "56855"},
{"zone": "SC", "zip": "28031"},
{"zone": "TN", "zip": "84755"}]
const newObj = [{"zone": "WV", "zip": "55444"},
{"zone": "SC", "zip": "28031"}]
array = array.concat(newObj.filter(x => !array.some(y => JSON.stringify(y) === JSON.stringify(x))))
console.log(array)
Upvotes: 1
Reputation: 918
By using underscore.js. You may try something like this:
let array = [
{"zone": "WV", "zip": "56855"},
{"zone": "SC", "zip": "28031"},
{"zone": "TN", "zip": "84755"}
];
let addMe1 = [{"zone": "SC", "zip": "28031"}, {"zone": "TN", "zip": "84755"}];
let addMe2 = [{"zone": "SC", "zip": "55555"}, {"zone": "TN", "zip": "88888"}];
// This will fail.
addMe1.forEach( item => !_.findWhere(array, item) ? array.push(item) : null);
// This will success.
addMe2.forEach( item => !_.findWhere(array, item) ? array.push(item) : null);
console.log(array);
<script src="https://fastcdn.org/Underscore.js/1.8.3/underscore-min.js"></script>
Upvotes: 1
Reputation: 92461
There are quick-to-develop, slow-to-run fixes, which involve searching through all the keys of all the objects every time. Or there's a slow-to-develop, quick-to-run solutions that build some sort of lookup so you don't have all the looping lookups. Here's a simple idea (more of a start of an idea) of the later.
Make a class (or object) that keeps a set of all known key/value pairs. This just concats them with a separator character (that shouldn't appear in the data). Now before adding, just do the constant-time lookup in the Set
to check :
let array = [
{"zone": "WV", "zip": "56855"},
{"zone": "SC", "zip": "28031"},
{"zone": "TN", "zip": "84755"}
]
class unqiueCollection {
constructor(arr, sep = "_"){
this.arr = []
this.sep = sep
this.unique_keys = new Set
arr.forEach((item) => this.add(item))
}
add(item) {
let key = item.zip + '_' + item.zone
if (!this.unique_keys.has(key)) {
this.unique_keys.add(key)
this.arr.push(item)
} else {
console.log("already in array")
}
}
}
let coll = new unqiueCollection(array)
// won't add
coll.add({"zone": "SC", "zip": "28031"})
coll.add({"zip": "28031", "zone": "SC"})
// will add
coll.add({"zone": "AK", "zip": "99577"})
console.log(coll.arr)
This assumes all objects will just consists of zip and zone. If your items are more complex, of course the key and logic to make the keys will need to be more complex to decide what constitutes unique.
Upvotes: 0
Reputation: 1976
Apart right answers already given, there's a mistake in your if statement (item.zip instead of zone.zip) and a misunderstanding of the filter
method (return true to keep and false to leave). So, if sticking on filter :
let valids = addMe.filter(function(element) {
for(let i=0; i < array.length; i++) {
if(item.zone === element.zone && item.zip === element.zip) return false // throw the item
}
return true; // keep the item
});
array.push(valids);
And a shorter way with findIndex for modern browser without filter :
for(let i = 0; i < addMe.length; i++) {
let index = array.findIndex(item => item.zone === element.zone && item.zip === element.zip);
// will return index of the matching item or -1
if(index < 0) array.push(element); // Add it and you're done
// or better to avoid array search inflation on already added elements
// It will remove element from addMe
addMe.splice(i,1);
}
// In case use of splice
array.push(addMe);
some
method is also a good approach of working on array instead of addMe.
Upvotes: 0
Reputation: 479
You can use native javascript, find() method in ECMAScript 6:
let array = [{"zone": "WV", "zip": "56855"}, {"zone": "SC", "zip": "28031"}, {"zone": "TN", "zip": "84755"}],
addMe = [{"zone": "SC", "zip": "28031"}, {"zone": "TN", "zip": "84755"}];
addMe.forEach(place => {
if (array.find((element) => element.zone == place.zone) === undefined) {
array.push(place);
}
});
Upvotes: 0
Reputation: 169
You could do this
if(myArray !== undefined && myArray.length != 0) {
//your code here
}
Upvotes: -1
Reputation: 33736
An alternative could be the function some
to capture at least one object where not every
value are equal.
let array = [{"zone": "WV", "zip": "56855"}, {"zone": "SC", "zip": "28031"}, {"zone": "TN", "zip": "84755"}],
addMe = [{"zone": "SC", "zip": "28031"}, {"zone": "TN", "zip": "84755"}];
addMe.forEach(o => {
if (!array.some(a => Object.keys(a).every(k => a[k] === o[k]))) array.push(o);
});
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 2