0

I have an array of dictionaries (from server). Then I get a one dictionary from database - and I need to find a this dictionary (from database) in array.

array.indexOf(dict) - it does not work, I think it's because dictionaries has different hidden fields

Get and compare strings ( toString() ) - does not work

If use a filter:

array.filter(function(dictFromArr){
  return dictFromArr.id == dict.id && ...
});

Does not fit, because so many fields.

Does anyone know how else to compare dictionaries?

Lola
  • 2,591
  • 6
  • 24
  • 49
  • Can you add an example of what this array of dictionaries looks like? Or more to the point, can't you just compare on one _unique_ id in your filter function rather than all of them? – Andy Sep 01 '15 at 11:57
  • @Andy example of what this array of dictionaries - very large and has a complicated structure - and it would take too much space here – Lola Sep 01 '15 at 12:09
  • @Maria, it looks like you didn't understand Andy's question. If these ids are unique database ids, then you could just look at the ids to tell if it's the same object or not. If the ids are unique, the "large and complicated structure" doesn't matter. – mik01aj Sep 02 '15 at 14:23

3 Answers3

0

To search an array you have to traverse it using O(n) operation, so filter is a viable option. An algorithm, that returns when it finds the object, will improve the performance sometimes, but the worst cast scenario (item not found) is still O(n):

function getObjectFromArray(array, object) {
    for(var i = 0; i < array.length; i++) { // traverse the array
        if(array[i].id === object.id) { // compare ids 
            return array[i]; // if id exist return element
        }
    }

    return null; // if not found return null
}

Usage:

getObjectFromArray(array, dict);
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
0

I guess you could try comparing arrays of keys and values of each array dictionary against your model dictionary. Not particularly efficient but gets the job done:

// return the object keys
function getKeys(obj) {
    return Object.keys(obj);
}

// using the keys, return the object values
function getVals(keys, obj) {
    return keys.map(function (el) {
        return obj[el];
    });
}

function isMatch(arr1, arr2) {

  // match the array lengths and that the values at each
  // index in arr1 match those in arr2
  return arr1.length === arr2.length && arr1.every(function (el, i) {
    return arr1[i] === arr2[i];
  });
}

function find(arr, obj) {

    // grab the object keys and values
    var oKeys = getKeys(obj);
    var oVals = getVals(oKeys, obj);

    // filter out the object where both the keys and
    // the values match
    return arr.filter(function (c) {
      var cKeys = getKeys(c);
      var cVals = getVals(cKeys, c);
      return isMatch(oKeys, cKeys) && isMatch(oVals, cVals);
    })[0] || 'no match';
}

find(arr, obj);

DEMO

Andy
  • 61,948
  • 13
  • 68
  • 95
0

That's because indexOf uses strict comparison (===) so even [{a:1}].indexOf({a:1}) returns -1.

Comparing strings is a bad idea (because toString returns [Object object] by default). Even comparing JSON strings is a bad idea because JSON.stringify({b:1,a:1}) !== JSON.stringify({a:1,b:1}) although the objects are obviously equal.

If you'd be willing to pull a new library to your project, you could use lodash with its _.isEqual and _.find functions. Note that you don't have to pull whole lodash if you don't want to - you can use the lodash.isequal npm package (and there is a separate package for every other function in lodash, too).

Alternatively, you could write a recursive function to compare them. The function would iterate through all the keys in the objects, and if the values are both objects, it should recurse. But this way, imho, makes sense only as a programming exercise (still, a good one).

See also this great answer for more details about comparing objects in JS (note how big the code is! That's why you probably don't want to implement it yourself).

Community
  • 1
  • 1
mik01aj
  • 11,928
  • 15
  • 76
  • 119