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

JavaScript: Remove duplicates of objects sharing same property value

我有一组对象,我想根据特定的 key:value 对 trim 向下移动。我想创建一个数组,其中每个特定的 key:value 对只包含一个对象。将副本中的哪个对象复制到新数组并不一定重要。

比如我想trim基于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 函数可以循环执行此操作?

EDIT: The property to filter on is nested within another property.

我认为 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');

Returns:

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

removeDuplicates(arrayWithDuplicates, 'color');

Returns:

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

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

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);

使用 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;
    });
}

在我处理对象数组时,没有一个函数可以为您执行此操作,而且也没有将重复项作为重复项删除的规则。

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

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

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

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 如果您需要提供关于要删除的项目的首选项,您可以定义额外的参数和逻辑,这些参数和逻辑将在添加到 return 值之前进行额外的 属性 检查。

希望对您有所帮助!

您可以为此使用 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; });

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

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);
    }
});

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

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

_.uniqBy(arrayWithDuplicates, 'color')

它将return一个具有唯一值的数组

这是打字稿方式

    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');
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);

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

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

此处“id”是您的唯一标识符

这只是另一个 'feature' 基于 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;
};

希望在根据单个对象 属性 值过滤掉对象时,即使不是所有数组,这也适用于大多数数组。

尝试以下功能:

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