Filter array of objects for unique items

Given an array of objects:

var arr = [
  {a: "foo", b: "bar", c: "baz" },
  {a: "foo", b: "bar", c: "qux" },
  {a: "foo", b: "bar", c: "baz" },
  {a: "foo", b: "bar", c: "qux" },
  {a: "bar", b: "foo", c: "qux" },
  {a: "bar", b: "qux", c: "foo" },
  {a: "bar", b: "foo", c: "qux" }
];

      

The array must be filtered, so only unique objects remain:

var arr = [
  {a: "foo", b: "bar", c: "baz" },
  {a: "foo", b: "bar", c: "qux" },
  {a: "bar", b: "foo", c: "qux" },
  {a: "bar", b: "qux", c: "foo" }
];

      

For arrays of simple strings, I use

arr.filter(function (value, index, self) { 
    return self.indexOf(value) === index;
}

      

but that doesn't work with objects. All properties should be mapped in my case. Think you need some kind of deep comparison?

+3


source to share


3 answers


If your objects have the same keys, you can use the lodash function or underscore _.findWhere

:

Performs a deep comparison between each item in the collection and the original object, returning the first item with equivalent property values.

var arr = [
  {a: "foo", b: "bar", c: "baz" },
  {a: "foo", b: "bar", c: "qux" },
  {a: "foo", b: "bar", c: "baz" },
  {a: "foo", b: "bar", c: "qux" },
  {a: "bar", b: "foo", c: "qux" },
  {a: "bar", b: "qux", c: "foo" },
  {a: "bar", b: "foo", c: "qux" }
];

function uniqueObjects(arr) {
  var u = [];
  arr.forEach(function(obj) {
    if (!_.findWhere(u, obj)) {
      u.push(obj);
    }
  });
  return u
}

document.getElementById('result').innerHTML = JSON.stringify(uniqueObjects(arr),null,2);
      

<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.7.0/lodash.min.js"></script>
<pre id='result'></pre>
      

Run codeHide result




If not, a deep comparison can be made using _.matches

both directions:

var arr = [
  {a: "foo", b: "bar", c: "baz" },
  {a: "foo", b: "bar", c: "qux" },
  {a: "foo", b: "bar", c: "baz" },
  {a: "foo", b: "bar", c: "qux" },
  {a: "bar", b: "foo", c: "qux" },
  {a: "bar", b: "qux", c: "foo" },
  {a: "bar", b: "foo", c: "qux" },
  // Missing property
  {a: "foo", b: "bar" },
  // Ordering
  {a: "foo", c: "qux" },
  {c: "qux", a: "foo" }
];

function uniqueObjects(arr) {
  var u = [];
  arr.forEach(function(obj) {
    if (!u.filter(deepCompare(obj)).length) {
      u.push(obj);
    }
  });
  return u;
}

function deepCompare(obj) {
  return function(source) {
    return _.matches(obj)(source) && _.matches(source)(obj);
  };
}

document.getElementById('result').innerHTML = JSON.stringify(uniqueObjects(arr),null,2);
      

<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.7.0/lodash.min.js"></script>
<pre id='result'></pre>
      

Run codeHide result


0


source


I used the approach I mentioned in my comment.



var arr = [
  {c: "baz", a: "foo", b: "bar" },
  {c: "qux", a: "foo", b: "bar" },
  {c: "baz", b: "bar", a: "foo" },
  {c: "qux", b: "bar", a: "foo" },
  {a: "bar", c: "qux", b: "foo" },
  {a: "bar", c: "foo", b: "qux" },
  {a: "bar", b: "foo", c: "qux" }
];

var modified = arr.map(function (value) {
    var result = [];
    var keys = Object.keys(value).sort();

    for (var i = 0; i < keys.length; i++) {
        result.push(value[keys[i]]);
    }
    return result.join('');
});

for (var i = (modified.length - 1); i >= 0; i--) {
    if (modified.indexOf(modified[i]) !== i) {
        arr.splice(i, 1);
    }
}


alert(JSON.stringify(arr));
      

Run codeHide result


-2


source


Use lodash! https://lodash.com/docs#uniq

Creates a duplicate version of the array using SameValueZero for equality comparison, which stores only the first occurrence of each element. Providing true to isSorted performs a faster search algorithm for sorted arrays. If an iterative function is provided, it is called for each element in the array to generate a criterion against which uniqueness is calculated. The iterator is bound to thisArg and is called with three arguments: (value, index, array).

Include it in your HTML <script src="bower_components/lodash/lodash.js"></script>

Then in your controller.

var filteredArray = _.uniq(arr, function(item, key, a) { 
    return item.a;
});

      

http://jsfiddle.net/8xp3o7b3/3/

-3


source







All Articles