基于多个键的重复值,从对象数组中删除元素

9

我有一个像这样的对象数组 -

var arr = [
    { type_id: "3", full_empty:"true", quantity:1},
    { type_id: "3", full_empty:"true", quantity:1},
    { type_id: "9", full_empty:"true", quantity:4},
    { type_id: "9", full_empty:"false", quantity:4},
    { type_id: "9", full_empty:"true", quantity:4},
    { type_id: "9", full_empty:"true", quantity:4},
    { type_id: "9", full_empty:"true", quantity:4}
];

我希望删除拥有相同的type_idfull_empty值的重复项。结果应该是这样的 -
var arr = [
    { type_id: "3", full_empty:"true", quantity:1},
    { type_id: "9", full_empty:"true", quantity:4},
    { type_id: "9", full_empty:"false", quantity:4},
];

我已经搜索并找到了一些解决方案,但其中一些是用于删除重复的键或仅基于一个键的重复值来删除重复项的。有些需要外部库。还有一些解决方案我无法理解。是否有任何简单的方法在纯JavaScript中执行此操作? 更好地理解编辑 - 我已阅读这个问题。该问题的被接受的答案只适用于查找单个键的重复项。在我的情况下,我必须查找多个键的重复项。

可能是 Remove duplicates from an array of objects in javascript 的重复问题。 - Rohit416
@Rohit416 我尝试过实施那个解决方案。但它只在一个键中搜索重复值。而在我的情况下,我必须在多个键中搜索重复值。 - ni8mr
但是如果该数组是 var arr = [ { type_id: "3", full_empty:"true", quantity:1}, { type_id: "3", full_empty:"true", quantity:2}, ... ]; 你期望得到什么结果? - Van M. Tran
9个回答

13

您可以使用纯函数通过使用 Array.some()Array.reduce() 将您的输入数组减少为不同元素的数组,如下所示。

    var arr = [
        { type_id: "3", full_empty:"true", quantity:1},
        { type_id: "3", full_empty:"true", quantity:1},
        { type_id: "9", full_empty:"true", quantity:4},
        { type_id: "9", full_empty:"false", quantity:4},
        { type_id: "9", full_empty:"true", quantity:4},
        { type_id: "9", full_empty:"true", quantity:4},
        { type_id: "9", full_empty:"true", quantity:4}
    ];

    var a = arr.reduce(function (accumulator, current) {
      if (checkIfAlreadyExist(current)) {
        return accumulator
      } else {
        return accumulator.concat([current]);
      }
      
      function checkIfAlreadyExist(currentVal) {
        return accumulator.some(function(item){
          return (item.type_id === currentVal.type_id &&
                  item.full_empty === currentVal.full_empty);
        });
      }
    }, []);
        
    console.log(a);

简洁的ES6语法

可以使用ES6箭头函数和展开运算符来编写更简洁的reduce,如下所示:


var arr = [
            { type_id: "3", full_empty:"true", quantity:1},
            { type_id: "3", full_empty:"true", quantity:1},
            { type_id: "9", full_empty:"true", quantity:4},
            { type_id: "9", full_empty:"false", quantity:4},
            { type_id: "9", full_empty:"true", quantity:4},
            { type_id: "9", full_empty:"true", quantity:4},
            { type_id: "9", full_empty:"true", quantity:4}
        ];

var a = arr.reduce((accumulator, current) => {
  if (checkIfAlreadyExist(current)) {
    return accumulator;
  } else {
    return [...accumulator, current];
  }

  function checkIfAlreadyExist(currentVal) {
    return accumulator.some((item) => {
      return (item.type_id === currentVal.type_id &&
              item.full_empty === currentVal.full_empty);
    });
  }
}, []);
            
console.log(a);


谢谢,你的回答解决了这个问题。许多答案缺少一个关键点——如果存在多个关键字,我必须搜索重复项。 - ni8mr
@ni8mr 不客气 :). 如果这个答案对您有用,请接受它。 - Aditya Singh

5
尽管还有其他解决方案,但我建议使用哈希表,将type_idfull_empty作为键,并在发现新的键时将哈希设置为true。结合Array#filter使用,您可以获得一个包含独特项的新数组。

var arr = [{ type_id: "3", full_empty: "true", quantity: 1 }, { type_id: "3", full_empty: "true", quantity: 1 }, { type_id: "9", full_empty: "true", quantity: 4 }, { type_id: "9", full_empty: "false", quantity: 4 }, { type_id: "9", full_empty: "true", quantity: 4 }, { type_id: "9", full_empty: "true", quantity: 4 }, { type_id: "9", full_empty: "true", quantity: 4 }],
    filtered = arr.filter(function (a) {
        var key = a.type_id + '|' + a.full_empty;
        if (!this[key]) {
            this[key] = true;
            return true;
        }
    }, Object.create(null));

console.log(filtered);

ES6

var arr = [{ type_id: "3", full_empty: "true", quantity: 1 }, { type_id: "3", full_empty: "true", quantity: 1 }, { type_id: "9", full_empty: "true", quantity: 4 }, { type_id: "9", full_empty: "false", quantity: 4 }, { type_id: "9", full_empty: "true", quantity: 4 }, { type_id: "9", full_empty: "true", quantity: 4 }, { type_id: "9", full_empty: "true", quantity: 4 }],
    filtered = arr.filter(
        (temp => a =>
            (k => !temp[k] && (temp[k] = true))(a.type_id + '|' + a.full_empty)
        )(Object.create(null))
    );

console.log(filtered);


1
这不如Nina答案那么出色,但可以被注意到并作为一个新答案。

var arr = [ { type_id: "3", full_empty: "true", quantity: 1 }, { type_id: "3", full_empty: "true", quantity: 1 }, { type_id: "9", full_empty: "true", quantity: 4 }, { type_id: "9", full_empty: "false", quantity: 4}, { type_id: "9", full_empty: "true", quantity: 4 }, { type_id: "9", full_empty: "true", quantity: 4 }, { type_id: "9", full_empty: "true", quantity: 4}];

var dict = {}, result = [];

arr.forEach((i, key) => {
  !dict[(key = i.type_id + i.full_empty)] 
      && (dict[key] = result.push(i));
})
console.log(result)


1
//To search the element is already exisit or not.(to remove Duplicate)
    function searchExisting(type_id,full_empty,newArray){
        for(var i=0;i<newArray.length;i++){
            if(newArray[i].type_id==type_id && newArray[i].full_empty==full_empty){
                return true;
            }
        }
        return false;
    }

//loop through every element and push it into new array
    var arr2=[];
    for(var i=0;i<arr.length;i++){
        if(!searchExisting(arr[i].type_id,arr[i].full_empty,arr2)){
            arr2.push(arr[i]);
        }
    }
    console.log(arr2)

谢谢,你的回答也有所帮助。 - ni8mr

1
你可以使用 findforEach 来创建一个新的数组,其中包含重复的值。
希望这个片段对你有用。
var arr = ["Json Array object as supplied in the question"];

// A new array which will contain unique json object
var newArray = [];

//Loop through each of the object in the original array

arr.forEach(function(item) {
    // If newArray .length is zero then just push the first element
    // else in newArray find if a json object already exist which have same
    // type_id & full_empty. If it does not exist it will return undefined
    if (newArray.length !== 0) {
        var _isPresent = newArray.find(function(secItem) {
            return secItem.type_id === item.type_id && secItem.full_empty === item.full_empty
        })
        // If element is not present then push this json pbject
        if (_isPresent == undefined) {
            newArray.push(item)
        }
    } else {  // this will execute only once when newArray length is 0

        newArray.push(item)
    }
})
console.log(newArray)

JSFIDDLE


0
数组对象上有filter和map方法。你可以使用filter来筛选出你想要的不活跃属性。它是一个布尔评估,返回一个"过滤"后的新数组。
Egghead.IO网站上发布了一个很棒的视频教程,真正地解析了这个概念。

0

var arr = [
    { type_id: "3", full_empty:"true", quantity:1},
    { type_id: "3", full_empty:"true", quantity:1},
    { type_id: "9", full_empty:"true", quantity:4},
    { type_id: "9", full_empty:"false", quantity:4},
    { type_id: "9", full_empty:"true", quantity:4},
    { type_id: "9", full_empty:"true", quantity:4},
    { type_id: "9", full_empty:"true", quantity:4}
];

let op = [];

arr.forEach((el) => {
  if (isNotExist(el)){
    op.push(el)
  }
  function isNotExist(obj){
    return op.every(el => JSON.stringify(el) !== JSON.stringify(obj) )
   
  }
})

console.log(op)


0

如果您不想涉及代码,可以使用以下片段:

var sDat = [
{ sid:12, scode:"code", sname:"Deep" },
{ sid:12, scode:"code", sname:"Anand" },
{ sid:139, scode:"code", sname:"Singh"}
];

function cleanup(arr, prop) {
var new_arr = [];
var lookup  = {};

for (var i in arr) {
    lookup[arr[i][prop]] = arr[i];
}

for (i in lookup) {
    new_arr.push(lookup[i]);
}

return new_arr;
}

var n = cleanup(sDat, 'sid');
alert(n);

我希望这对你有用。

它能运行,但是使用你的代码只能检查一个键中是否有重复值。我需要同时检查多个键中是否有重复值。顺便说一下,谢谢。 - ni8mr

0

这是我修改过的Aditya Singh的答案

var arr = [
                { type_id: "3", full_empty:"true", quantity:1},
                { type_id: "3", full_empty:"true", quantity:1},
                { type_id: "9", full_empty:"true", quantity:4},
                { type_id: "9", full_empty:"false", quantity:4},
                { type_id: "9", full_empty:"true", quantity:4},
                { type_id: "9", full_empty:"true", quantity:4},
                { type_id: "9", full_empty:"true", quantity:4}
            ];


    var a = arr.reduce((accumulator, current) => {

     const isAlreadyExist = accumulator.some(item => (
      item.type_id === currentVal.type_id && item.full_empty === currentVal.full_empty
     ))

     return isAlreadyExist(current) ? accumulator : [...accumulator, current];
    }, []);

    console.log(a);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接