1

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?

3
  • 1
    At this point, I'd advocate not using an array and actually using a (probably hashing) data structure that is designed for fast retrieval and comparison. Something with zip code as primary bin for instance, and doesn't waste time so much "comparing" but simply testing "does zipcodes[code] exist? no. done, not in this collection. does it exist? okay does zipcodes[code][statecode] exist? no? done, not in this collection. does it exist? okay, ..."CommentedNov 29, 2018 at 23:24
  • @Mike'Pomax'Kamermans thanks.. one question, a hashing data structure what's that? I found this.. is this along the lines of what you're thinking? medium.freecodecamp.org/…
    – ToddT
    CommentedNov 29, 2018 at 23:31
  • 1
    Don't implement a hashing data structure yourself unless you know how and why hashing works, and how to optimize the hashing algorithm for your data. If not, just pick one off the shelf (typically, find one on npmjs.com). But in this case, you probably don't even need hashing: you already have values in those objects that act as identifiers.CommentedNov 29, 2018 at 23:33

7 Answers 7

2

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; }

    1

    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) 
    3
    • check this out.. your solution works but instead of adding the object that passes into array its adding it as an array.. check out this jsfiddle jsfiddle.net/Trimakas/26ohawmb/1 any idea how I can just add the object and not the array?
      – ToddT
      CommentedNov 30, 2018 at 21:42
    • ahh its the filter method that's creating the array, and I can just use flat() and all is well.. thanks!!
      – ToddT
      CommentedNov 30, 2018 at 21:44
    • Or concat. Sorry I’m on my phone I couldn’t test. But indeed flat or concat ensures to not have that issue you pointed out
      – aquiseb
      CommentedNov 30, 2018 at 21:49
    1

    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>

      0

      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); } }); 
        0

        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.

          0

          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.

            -1

            You could do this

             if(myArray !== undefined && myArray.length != 0) { //your code here } 

              Start asking to get answers

              Find the answer to your question by asking.

              Ask question

              Explore related questions

              See similar questions with these tags.