【问题标题】:How can I check if the array of objects have duplicate property values?如何检查对象数组是否具有重复的属性值?
【发布时间】:2015-08-24 11:21:19
【问题描述】:

我在遍历数组时需要一些帮助,但我总是被卡住或重新发明轮子。

values = [
    { name: 'someName1' },
    { name: 'someName2' },
    { name: 'someName1' },
    { name: 'someName1' }
]

如何检查数组中是否有两个(或多个)相同的名称值?我不需要计数器,如果数组值不唯一,只需设置一些变量。请记住,数组长度是动态的,数组值也是动态的。

【问题讨论】:

  • @AmiTavory 至少有一个明显的区别—​​—该问题着眼于一组基元 (arr = [9, 9, 9, 111, 2, 3, 3, 3, 4, 4, 5, 7];),而这着眼于基于对象属性的重复数据删除。语义,也许,但那里的两个最高投票的答案并没有完全解决这种情况。 /giphy the more you know(我意识到这不会做任何事情)

标签: javascript arrays unique


【解决方案1】:

ECMA 脚本 6 版

如果您在支持 ECMA Script 6 的 Set 的环境中,那么您可以使用 Array.prototype.someSet 对象,像这样

let seen = new Set();
var hasDuplicates = values.some(function(currentObject) {
    return seen.size === seen.add(currentObject.name).size;
});

在这里,我们将每个对象的name 插入到Set 中,并检查添加前后的size 是否相同。这是因为Set.size 返回一个基于唯一数据的数字(set 仅在数据唯一时添加条目)。如果/当您有重复的名称时,大小不会增加(因为数据不会是唯一的),这意味着我们已经看到了当前名称并且它将返回 true。


ECMA 脚本 5 版本

如果你没有 Set 支持,那么你可以使用普通的 JavaScript 对象本身,像这样

var seen = {};
var hasDuplicates = values.some(function(currentObject) {

    if (seen.hasOwnProperty(currentObject.name)) {
        // Current name is already seen
        return true;
    }

    // Current name is being seen for the first time
    return (seen[currentObject.name] = false);
});

同样可以简洁写成这样

var seen = {};
var hasDuplicates = values.some(function (currentObject) {
    return seen.hasOwnProperty(currentObject.name)
        || (seen[currentObject.name] = false);
});

注意:在这两种情况下,我们都使用Array.prototype.some,因为它会短路。当它从函数中得到一个真值时,它会立即返回true,它不会处理其余的元素。

【讨论】:

  • 有趣的方法,使用hasOwnProperty。我在其他一些答案中看到您评论说indexOf 在大型阵列中的性能很差。您建议的上述 ES5 方式通常对较大的对象更友好吗?
  • @JoshBeam indexOf 将不得不迭代数组以找出元素是否存在,但任何使用散列的东西都会快得多。因此,如果数组很大,ES5 和 ES6 方式都会快得多。
  • 我如何确保它将处理其余的元素?
  • @AnnaSmother 如果要处理所有元素,那么使用forEach 并自己编写逻辑。
  • @chovy 问题是:“我如何检查数组中是否有两个(或更多)同名值?我不需要计数器,如果数组值不唯一,只需设置一些变量。”这与删除重复项无关。我认为这是最好的答案!
【解决方案2】:

您可以使用map 仅返回名称,然后使用此forEach 技巧检查它是否至少存在两次:

var areAnyDuplicates = false;

values.map(function(obj) {
    return obj.name;
}).forEach(function (element, index, arr) {
    if (arr.indexOf(element) !== index) {
        areAnyDuplicates = true;
    }
});

Fiddle

【讨论】:

  • indexOf 如果数组很大,性能会很差。
【解决方案3】:

使用array.prototype.maparray.prototype.some

var values = [
    { name: 'someName1' },
    { name: 'someName2' },
    { name: 'someName4' },
    { name: 'someName2' }
];

var valueArr = values.map(function(item){ return item.name });
var isDuplicate = valueArr.some(function(item, idx){ 
    return valueArr.indexOf(item) != idx 
});
console.log(isDuplicate);

【讨论】:

  • indexOf 如果数组很大,性能会很差。
  • 我将返回部分替换为:return valueArr.indexOf(item, idx + 1) !== -1
  • 另一个选项可以是new Set(arr).size !== arr.length 来检查数组是否有重复。
  • @JoelFernando - 答案写于 6 年前及以下,有人添加了与 Set 一起使用的 ES6 答案。您的答案将适用于一系列原语。这里的问题是关于一组对象,其中内部属性是我们不想复制的对象。
【解决方案4】:

使用 Underscore.js 可以通过几种方式使用 Underscore。这是其中之一。检查数组是否已经是唯一的。

function isNameUnique(values){
    return _.uniq(values, function(v){ return v.name }).length == values.length
}

使用原生 JavaScript 通过检查数组中是否没有重复的名称。

function isNameUnique(values){
    var names = values.map(function(v){ return v.name });
    return !names.some(function(v){ 
        return names.filter(function(w){ return w==v }).length>1 
    });
}

【讨论】:

    【解决方案5】:

    尝试一个简单的循环:

    var repeat = [], tmp, i = 0;
    
    while(i < values.length){
      repeat.indexOf(tmp = values[i++].name) > -1 ? values.pop(i--) : repeat.push(tmp)
    }
    

    Demo

    【讨论】:

    • 这只是以它们的重复数据删除数组结束。
    【解决方案6】:

    要知道简单数组是否有重复,我们可以比较相同值的 firstlast 索引:

    功能:

    var hasDupsSimple = function(array) {
    
        return array.some(function(value) {                            // .some will break as soon as duplicate found (no need to itterate over all array)
           return array.indexOf(value) !== array.lastIndexOf(value);   // comparing first and last indexes of the same value
        })
    }
    

    测试:

    hasDupsSimple([1,2,3,4,2,7])
    // => true
    
    hasDupsSimple([1,2,3,4,8,7])
    // => false
    
    hasDupsSimple([1,"hello",3,"bye","hello",7])
    // => true
    

    对于对象数组,我们需要先将对象值转换为简单数组:

    使用map将对象数组转换为简单数组:

    var hasDupsObjects = function(array) {
    
      return array.map(function(value) {
        return value.suit + value.rank
    
      }).some(function(value, index, array) { 
           return array.indexOf(value) !== array.lastIndexOf(value);  
         })
    }
    

    测试:

    var cardHand = [
      { "suit":"spades", "rank":"ten" },
      { "suit":"diamonds", "rank":"ace" },
      { "suit":"hearts", "rank":"ten" },
      { "suit":"clubs", "rank":"two" },
      { "suit":"spades", "rank":"three" },
    ]
    
    hasDupsObjects(cardHand);
    // => false
    

    var cardHand2 = [
      { "suit":"spades", "rank":"ten" },
      { "suit":"diamonds", "rank":"ace" },
      { "suit":"hearts", "rank":"ten" },
      { "suit":"clubs", "rank":"two" },
      { "suit":"spades", "rank":"ten" },
    ]
    
    hasDupsObjects(cardHand2);
    // => true
    

    【讨论】:

    • 如何找到索引以及最新的重复值
    • @SystemsRebooter,谢谢!!正是我想要的。
    【解决方案7】:

    如果您正在寻找布尔值,最快的方法是

    var values = [
        { name: 'someName1' },
        { name: 'someName2' },
        { name: 'someName1' },
        { name: 'someName1' }
    ]
    
    // solution
    var hasDuplicate = false;
    values.map(v => v.name).sort().sort((a, b) => {
      if (a === b) hasDuplicate = true
    })
    console.log('hasDuplicate', hasDuplicate)

    【讨论】:

      【解决方案8】:
      //checking duplicate elements in an array
      var arr=[1,3,4,6,8,9,1,3,4,7];
      var hp=new Map();
      console.log(arr.sort());
      var freq=0;
      for(var i=1;i<arr.length;i++){
      // console.log(arr[i-1]+" "+arr[i]);
      if(arr[i]==arr[i-1]){
      freq++;
      
      }
      else{
      hp.set(arr[i-1],freq+1);
      freq=0;
      }
      }
      console.log(hp);
      

      【讨论】:

      • 使用节点 scriptname.js 复制粘贴运行
      【解决方案9】:

      在 TS 和 ES6 中,您可以创建一个具有唯一属性的新 Set,并将其大小与原始数组进行比较。

      const values = [
        { name: 'someName1' },
        { name: 'someName2' },
        { name: 'someName3' },
        { name: 'someName1' }
      ]
      
      const uniqueValues = new Set(values.map(v => v.name));
      
      if (uniqueValues.size < values.length) {
        console.log('duplicates found')
      }

      【讨论】:

      • 这其实是最好的答案
      【解决方案10】:

      添加更新的 es6 函数以检查数组中的唯一值和重复值。这个函数是模块化的,可以在整个代码库中重用。感谢以上所有帖子。

      
      
      /* checks for unique keynames in array */
      const checkForUnique = (arrToCheck, keyName) => {
          /* make set to remove duplicates and compare to  */
        const uniqueValues = [...new Set(arrToCheck.map(v => v[keyName]))];
        if(arrToCheck.length !== uniqueValues.length){
          console.log('NOT UNIQUE')
          return false
        }
        return true
      }
      
      
      let arr = [{name:'joshua'},{name:'tony'},{name:'joshua'}]
      
      /* call function with arr and key to check for  */
      let isUnique = checkForUnique(arr,'name')
      
      
      
      
      

      【讨论】:

        【解决方案11】:

        试试这个功能,它通过一步删除重复项来扩展您的原始问题。您会得到一个删除了重复项的返回数组。

        const test = [
            { name: 'someName1' },
            { name: 'someName1' },
            { name: 'someName2' },
            { name: 'someName3' }
        ]
        
        function removeDup(arrayOfObjects) {
          if (new Set(arrayOfObjects.map((v) => v.name)).size < arrayOfObjects.length) {
                  const _set = new Set();
                  const _data = arrayOfObjects;
                  for (const i in _data) {
                    _set.add(JSON.stringify(_data[i]));
                  }
                  return Array.from(_set).map((i) =>
                    JSON.parse(i)
                  );
                }
        }
        
        const res = removeDup(test)
        console.log(res)

        【讨论】:

          猜你喜欢
          • 2020-06-08
          • 2013-12-26
          • 2014-05-08
          • 1970-01-01
          • 2017-10-09
          • 2021-08-19
          • 2013-07-03
          相关资源
          最近更新 更多