【问题标题】:How can I get a unique array based on object property using underscore如何使用下划线获取基于对象属性的唯一数组
【发布时间】:2013-12-23 08:23:59
【问题描述】:

我有一个对象数组,我想从中获取一个新数组,该数组仅基于单个属性是唯一的,有没有简单的方法来实现这一点?

例如。

[ { id: 1, name: 'bob' }, { id: 1, name: 'bill' }, { id: 1, name: 'bill' } ]

将导致 2 个名称 = bill 的对象被删除一次。

【问题讨论】:

    标签: javascript underscore.js


    【解决方案1】:

    使用uniq 函数

    var destArray = _.uniq(sourceArray, function(x){
        return x.name;
    });
    

    或单行版本

    var destArray = _.uniq(sourceArray, x => x.name);
    

    来自文档:

    生成数组的无重复版本,使用 === 来测试对象是否相等。如果您事先知道数组已排序,则为 isSorted 传递 true 将运行更快的算法。如果您想根据转换计算唯一项,请传递一个迭代器函数。

    在上面的示例中,函数使用对象名称来确定唯一性。

    【讨论】:

    • 您好,是否可以检查多个属性的唯一性,例如上面的例子,说 id 和 name 两者?
    • @APaul 检查我给出的答案。希望你能找到你真正想要的东西。
    • 从下划线(1.10.2)的最新版本开始,语法如下:_.uniq(array, [isSorted], [iteratee]),即你应该将函数作为第三个论点。请参阅文档underscorejs.org/#uniq
    • lodash uniq 在这里中断!我花了一个小时调试。你必须使用 uniqBy 因为 lodash 不是下划线的替代品,它在一些事情上默默地失败了。
    【解决方案2】:

    如果您更喜欢在不使用 Lodash 且不冗长的情况下自己做事,请尝试使用可选 uniq by property 的 uniq 过滤器:

    const uniqFilterAccordingToProp = function (prop) {
        if (prop)
            return (ele, i, arr) => arr.map(ele => ele[prop]).indexOf(ele[prop]) === i
        else
            return (ele, i, arr) => arr.indexOf(ele) === i
    }
    

    然后,像这样使用它:

    const obj = [ { id: 1, name: 'bob' }, { id: 1, name: 'bill' }, { id: 1, name: 'bill' } ]
    obj.filter(uniqFilterAccordingToProp('abc'))
    

    或者对于普通数组,只需省略参数,同时记住调用:

    [1,1,2].filter(uniqFilterAccordingToProp())

    【讨论】:

      【解决方案3】:

      如果您想检查所有属性,那么 lodash 4 自带 _.uniqWith(sourceArray, _.isEqual)

      【讨论】:

      • 2+ 属性怎么样,但不是所有属性?
      【解决方案4】:

      更好更快捷的方法

      var table = [
        {
          a:1,
          b:2
        },
        {
          a:2,
          b:3
        },
        {
          a:1,
          b:4
        }
      ];
      
      let result = [...new Set(table.map(item => item.a))];
      document.write(JSON.stringify(result));
      

      Found here

      【讨论】:

      • 感谢 Mudasar Rauf。不需要下划线 js 或任何其他库纯 JavaScript。但是使用 var 而不是 let 以便它可以在 IE 或旧浏览器中工作。
      • @SyedNasirAbbas Set 无论如何都不支持。
      • 这与 OP-s 请求略有不同,因为它返回 a 的唯一值,而我们应该获取 table 的所有具有唯一 a 属性的子级。结果的差异是[1, 2](当前)与[{ a: 1, b: 2 }, { a: 2, b: 3 }](预期)。
      • @kano 它正在记录第一条记录。否则最好的解决方案是使用 ColinE 回答的下划线,当您知道权衡时,这是一种快速的方法。
      • 它没有解决 OP 请求,因为它返回的是属性而不是对象
      【解决方案5】:

      你可以使用_.uniqBy函数

      var array = [ { id: 1, name: 'bob' }, { id: 2, name: 'bill' }, { id: 1, name: 'bill' },{ id: 2, name: 'bill' } ];
      
      var filteredArray = _.uniqBy(array,function(x){ return x.id && x.name;});
      
      console.log(filteredArray)
      <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js"></script>

      在上面的例子中,过滤是基于属性 id 和 name 组合的唯一性。

      如果一个对象有多个属性。 然后要根据特定属性找到唯一的对象数组,您可以按照这种在 _.uniqBy() 方法中组合属性的方法。

      【讨论】:

      • @el_pup_le 你能检查一下这个答案,如果这不是你所期望的,请告诉我。
      • 不起作用。 uniqBy 的回调函数需要返回该数据项的唯一值。您始终返回 true,这对于任何数据项都不是唯一的。试试这个返回${x.name}/{x.id};
      • @BruceJo ,我还包含了一个示例,用于演示解决方案并显示了预期的行为。问题是基于单个属性获取一组唯一对象。我给出的解决方案是通过在需要时考虑多个属性来使其独一无二。
      • 是的,这就是我理解您提出问题的方式。但你的答案只有name 是独一无二的。 x.id 总是!falsy,所以你的回报就是x.name。如果您想要 2 个属性的唯一性,那么 id: 1, name: bill 应该在结果中。它不是。尝试使用 return `${x.id}/${x.name]` 你会明白我的意思。
      【解决方案6】:

      我正在寻找一个不需要库的解决方案,并将它放在一起,所以我想我会在这里添加它。它可能并不理想,或者在所有情况下都有效,但它正在满足我的要求,因此可能会帮助其他人:

      const uniqueBy = (items, reducer, dupeCheck = [], currentResults = []) => {
        if (!items || items.length === 0) return currentResults;
        
        const thisValue = reducer(items[0]);
        
        const resultsToPass = dupeCheck.indexOf(thisValue) === -1 ?
          [...currentResults, items[0]] : currentResults;
          
        return uniqueBy(
          items.slice(1),
          reducer,
          [...dupeCheck, thisValue],
          resultsToPass,
        );    
      }
      
      const testData = [
        {text: 'hello', image: 'yes'},
        {text: 'he'},
        {text: 'hello'},
        {text: 'hell'},
        {text: 'hello'},
        {text: 'hellop'},
      ];
      
      const results = uniqueBy(
        testData,
        item => {
          return item.text
        },
      )
      
      console.dir(results)

      【讨论】:

      • “设置”看起来更好
      • @sonnenhaft Set 据我所知,您无法选择以编程方式确定唯一性
      【解决方案7】:

      如果您需要纯 JavaScript 解决方案:

      var uniqueProperties = {};
      
      var notUniqueArray = [ { id: 1, name: 'bob' }, { id: 1, name: 'bill' }, { id: 1, name: 'bill' } ];
      
      
      for(var object in notUniqueArray){
         uniqueProperties[notUniqueArray[object]['name']] = notUniqueArray[object]['id'];
      }
      
      var uniqiueArray = [];
      
      for(var uniqueName in uniqueProperties){
         uniqiueArray.push(
           {id:uniqueProperties[uniqueName],name:uniqueName});
      }
      
      //uniqiueArray
      

      【讨论】:

      • 一个纯 Javascript 解决方案。喜欢另类
      • 对我来说似乎是错误的。您假设属性名称只会出现一次?
      • @hasen 我认为您在这里没有这个想法。在浏览器控制台中执行代码或再次阅读 OP 问题。
      【解决方案8】:

      使用 ES6 的 id 属性的唯一数组:

      arr.filter((a, i) => arr.findIndex(b => b.id === a.id) === i);  // unique by id
      

      b.id === a.id替换为您的案例的相关比较

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-25
        • 1970-01-01
        • 2014-12-06
        • 2017-01-07
        相关资源
        最近更新 更多