JavaScript:删除共享相同属性值的对象的重复项

Posted

技术标签:

【中文标题】JavaScript:删除共享相同属性值的对象的重复项【英文标题】:JavaScript: Remove duplicates of objects sharing same property value 【发布时间】:2015-11-21 04:47:58 【问题描述】:

我有一组对象,我想根据特定的key:value 对来修剪它们。我想创建一个数组,其中每个特定的key:value 对只包含一个对象。将副本的哪个对象复制到新数组中并不一定重要。

例如,我想根据arrayWithDuplicatesprice 属性进行修剪,创建一个只包含每个值之一的新数组:

var arrayWithDuplicates = [
  "color":"red", 
    "size": "small",
    "custom": 
      "inStock": true,
      "price": 10
    
  ,
  "color":"green", 
    "size": "small",
    "custom": 
      "inStock": true,
      "price": 30
    
  ,
  "color":"blue", 
    "size": "medium",
    "custom": 
      "inStock": true,
      "price": 30
    
  ,
  "color":"red", 
    "size": "large",
    "custom": 
      "inStock": true,
      "price": 20
    
  
];

会变成:

var trimmedArray = [
  "color":"red", 
    "size": "small",
    "custom": 
      "inStock": true,
      "price": 10
    
  ,
  "color":"green", 
    "size": "small",
    "custom": 
      "inStock": true,
      "price": 30
    
  ,
  "color":"red", 
    "size": "large",
    "custom": 
      "inStock": true,
      "price": 20
    
  
];

是否有 javascript 或 Angular 函数可以循环执行此操作?

编辑:要过滤的属性嵌套在另一个属性中。

【问题讨论】:

Remove duplicates from an array of objects in javascript 的可能重复项 你看起来像下划线的 _.map 或 _.pluck 函数吗? underscorejs.org/#pluck 【参考方案1】:

我认为 Angular 中没有内置函数,但创建一个函数并不难:

function removeDuplicates(originalArray, objKey) 
  var trimmedArray = [];
  var values = [];
  var value;

  for(var i = 0; i < originalArray.length; i++) 
    value = originalArray[i][objKey];

    if(values.indexOf(value) === -1) 
      trimmedArray.push(originalArray[i]);
      values.push(value);
    
  

  return trimmedArray;


用法:

removeDuplicates(arrayWithDuplicates, 'size');

返回:

[
    
        "color": "red",
        "size": "small"
    ,
    
        "color": "blue",
        "size": "medium"
    ,
    
        "color": "red",
        "size": "large"
    
]

removeDuplicates(arrayWithDuplicates, 'color');

返回:

[
    
        "color": "red",
        "size": "small"
    ,
    
        "color": "green",
        "size": "small"
    ,
    
        "color": "blue",
        "size": "medium"
    
]

【讨论】:

如果您要检查 2 个属性的唯一性,例如: a: 1, b:1,如果数组中的任何其他对象有这个 - 它是重复的。【参考方案2】:

此函数通过返回一个新值从数组中删除重复值。

function removeDuplicatesBy(keyFn, array) 
    var mySet = new Set();
    return array.filter(function(x) 
        var key = keyFn(x), isNew = !mySet.has(key);
        if (isNew) mySet.add(key);
        return isNew;
    );


var values = [color: "red", color: "blue", color: "red", number: 2];
var withoutDuplicates = removeDuplicatesBy(x => x.color, values);
console.log(withoutDuplicates); // ["color": "red", "color": "blue"]

所以你可以像这样使用它

var arr = removeDuplicatesBy(x => x.custom.price, yourArrayWithDuplicates);

【讨论】:

谢谢!这绝对有效,但我只是编辑了我的问题,以反映这需要过滤嵌套属性(我的大量遗漏)。你的函数能处理吗? 谢谢,很好的答案,但显然如果使用 ES6,您可能会在没有某种 shim 或 polyfill 的旧浏览器中遇到问题(据我所知,箭头运算符是不可能的,因为它是一种语法错误)。要使其与 IE11 等老式浏览器一起使用,只需使用函数:removeDuplicatesBy(function(x) return x.custom.price; , yourArrayWithDuplicates);【参考方案3】:

使用Array.filter(),通过使用Object 作为散列来跟踪值,并过滤掉其值已包含在散列中的任何项目。

function trim(arr, key) 
    var values = ;
    return arr.filter(function(item)
        var val = item[key];
        var exists = values[val];
        values[val] = true;
        return !exists;
    );

【讨论】:

【参考方案4】:

在我的脑海中,没有一个函数可以为您执行此操作,因为您正在处理一组对象,并且没有规则将重复项作为重复项删除。

在您的示例中,您删除了带有 size: small 的那个,但如果您要使用循环来实现它,您很可能会在循环遍历数组时包含第一个并排除最后一个。

看看lodash 之类的库并创建一个使用其API 方法组合的函数来获得所需的行为可能非常值得。

这是一个可能的解决方案,您可以使用基本数组和过滤器表达式来检查在附加到返回结果之前是否将新项目视为重复项。

var arrayWithDuplicates = [
    "color":"red", "size": "small",
    "color":"green", "size": "small",
    "color":"blue", "size": "medium",
    "color":"red", "size": "large"
];

var reduce = function(arr, prop) 
  var result = [],
      filterVal,
      filters,
      filterByVal = function(n) 
          if (n[prop] === filterVal) return true;
      ;
  for (var i = 0; i < arr.length; i++) 
      filterVal = arr[i][prop];
      filters   = result.filter(filterByVal);
      if (filters.length === 0) result.push(arr[i]);
  
  return result;
;

console.info(reduce(arrayWithDuplicates, 'color'));

你可以查看一些关于数组过滤的文献here 如果您需要提供关于删除哪个项目的偏好,您可以定义额外的参数和逻辑,这些参数和逻辑将在添加到返回值之前进行额外的属性检查。

希望有帮助!

【讨论】:

【参考方案5】:

您可以为此使用underscore:

//by size:
var uSize = _.uniqBy(arrayWithDuplicates, function(p) return p.size; );

//by custom.price;
var uPrice = _.uniqBy(arrayWithDuplicates, function(p) return p.custom.price; );

【讨论】:

已更改为 _.uniqBy 并获得“唯一”属性名称。 _.uniqBy([ 'x': 1 , 'x': 2 , 'x': 1 ], 'x'); // => [ 'x': 1 , 'x': 2 ]【参考方案6】:

简单的解决方案虽然不是最高效的:

var unique = [];
duplicates.forEach(function(d) 
    var found = false;
    unique.forEach(function(u) 
        if(u.key == d.key) 
            found = true;
        
    );
    if(!found) 
        unique.push(d);
    
);

【讨论】:

【参考方案7】:

使用lodash,您可以轻松过滤掉它

第一个参数是您的数组,第二个参数是您的重复字段

_.uniqBy(arrayWithDuplicates, 'color')

它将返回一个具有唯一值的数组

【讨论】:

【参考方案8】:

这是打字稿的方式

    public removeDuplicates(originalArray:any[], prop) 
    let newArray = [];
    let lookupObject = ;

    originalArray.forEach((item, index) => 
        lookupObject[originalArray[index][prop]] = originalArray[index];
    );

    Object.keys(lookupObject).forEach(element => 
        newArray.push(lookupObject[element]);
    );
    return newArray;

let output = this.removeDuplicates(yourArray,'color');

【讨论】:

【参考方案9】:
for (let i = 0; i < arrayWithDuplicates.length; i++) 
     for (let j = i + 1; j < arrayWithDuplicates.length; j++) 
       if (arrayWithDuplicates[i].name === students[j].name) 
          arrayWithDuplicates.splice(i, 1);
       
     
    

this will work perfectly...and this will delete first repeated array.
To delete last repeated array we only have to change
 arrayWithDuplicates.splice(i, 1) ; into
 arrayWithDuplicates.splice(j, 1);

【讨论】:

【参考方案10】:

您可以使用 lodash 删除重复的对象:

 import * as _ from 'lodash';
  _.uniqBy(data, 'id');

这里 'id' 是您的唯一标识符

【讨论】:

【参考方案11】:

这只是基于 yvesmancera 解决方案的另一个“功能”(在我开始修改我自己的解决方案之后)还注意到我们目前只允许使用 IE 11,因此允许使用有限的 ES5。

var newArray = RemoveDuplicates(myArray,'Role', 2);

function RemoveDuplicates(array, objKey, rtnType) 
var list = [], values = [], value;
for (var i = 0; i < array.length; i++) 
    value = array[i][objKey];
    if(values.indexOf(value) === -1)
        list.push(array[i]);
        values.push(value);
        
    
    if(rtnType == 1)
        return list;
    return values;
;

希望在基于单个对象属性值过滤掉对象时,这对大多数数组(如果不是所有数组)都有效。

【讨论】:

【参考方案12】:

试试下面的功能:

function trim(items)
    const ids = [];
    return items.filter(item => ids.includes(item.id) ? false : ids.push(item.id));

【讨论】:

以上是关于JavaScript:删除共享相同属性值的对象的重复项的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 利用new Set()抽离数组中所有具备相同属性值的对象.

JavaScript 利用new Set()抽离数组中所有具备相同属性值的对象.

JavaScript 原型链学习原型对象存在的问题 与 组合使用构造函数和原型

JavaScript之面向对象学习六原型模式创建对象的问题,组合使用构造函数模式和原型模式创建对象

Qt:无法从 javascript 调用共享对象方法/属性

仅获取共享特定属性值的 Core Data 对象