过滤唯一元素的对象数组

时间:2015-04-27 10:33:51

标签: javascript arrays

给定一组对象:

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

应过滤数组,以便只保留唯一对象:

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

对于普通字符串数组,我使用

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

但这并不适用于对象。在我的情况下,必须比较所有属性。我想需要进行某种深度比较?

3 个答案:

答案 0 :(得分:0)

如果你的对象都有相同的键,你可以使用lodash或下划线的_.findWhere函数:

  

在集合中的每个元素与源对象之间执行深度比较,返回具有等效属性值的第一个元素。

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>

如果没有,可以通过两种方式使用_.matches进行深入比较:

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>

答案 1 :(得分:-2)

我使用了我在评论中提到的方法。

&#13;
&#13;
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));
&#13;
&#13;
&#13;

答案 2 :(得分:-3)

使用lodash! https://lodash.com/docs#uniq

  

创建一个无副本版本的数组,使用SameValueZero进行相等比较,其中只保留每个元素的第一个出现位置。为isSorted提供true为排序数组执行更快的搜索算法。如果提供了iteratee函数,则为数组中的每个元素调用它以生成计算唯一性的标准。 iteratee绑定到thisArg并使用三个参数调用:(value,index,array)。

将其包含在您的HTML中 <script src="bower_components/lodash/lodash.js"></script>

然后在你的控制器中。

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

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