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

时间:2023-02-11 04:45:29

I have an array of objects that I would like to trim down based on a specific key:value pair. I want to create an array that includes only one object per this specific key:value pair. It doesn't necessarily matter which object of the duplicates is copied to the new array.

我有一个对象数组,我想根据特定的键:值对减少。我想创建一个数组,每个特定的键只包含一个对象:值对。将重复项的哪个对象复制到新数组并不一定重要。

For example, I want to trim based on the price property of arrayWithDuplicates, creating a new array that only includes one of each value:

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

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

Would become:

会成为:

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

Is there a JavaScript or Angular function that would loop through and do this?

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

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

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

10 个解决方案

#1


2  

You can use underscore for this:

您可以使用下划线:

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

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

#2


19  

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

usage (EcmaScript6 arrow functions makes it look better):

用法(EcmaScript6箭头功能使它看起来更好):

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

EDIT: edited snippet not to use property name, but to use a key selector function, so you can reach nested properties.

编辑:编辑片段不使用属性名称,但使用键选择器功能,因此您可以达到嵌套属性。

#3


8  

I don't think there's a built-in function in Angular, but it isn't hard to create one:

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

}

Usage:

用法:

removeDuplicates(arrayWithDuplicates, 'size');

Returns:

返回:

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

And

removeDuplicates(arrayWithDuplicates, 'color');

Returns:

返回:

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

#4


6  

Use Array.filter(), keeping track of values by using an Object as a hash, and filtering out any items whose value is already contained in the hash.

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

#5


1  

using lodash you can filter it out easily

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

the first parameter will be your array and second will be your field with duplicates

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

_.uniqBy(arrayWithDuplicates, 'color')

it will return an array with unique value

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

#6


1  

Simple solution although not the most performant:

简单的解决方案,虽然不是最高性能:

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


0  

Off the top of my head there is no one function that will do this for you as you are dealing with an array of objects and also there is no rule for which duplicate would be removed as duplicate.

在你的头顶上没有任何一个函数可以为你做这件事,因为你正在处理一组对象,并且没有规则将重复删除哪些副本。

In your example you remove the one with size: small but if you were to implement this using a loop you'd most likely include the first and exclude the last as you loop through your array.

在你的例子中,你删除了一个size:small但是如果你要使用循环实现它,你很可能包括第一个并在循环遍历数组时排除最后一个。

It may very well be worth taking a look at a library such as lodash and creating a function that uses a combination of it's API methods to get the desired behaviour you want.

看看像lodash这样的库并创建一个使用它的API方法组合来获得所需行为的函数可能是非常值得的。

Here is a possible solution you could use making use of basic Arrays and a filter expression to check whether a new item would be considered a duplicate before being attached to a return result.

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

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

You can check out some literature on Array filtering here If you need to provide a preference on which item to remove you could define extra parameters and logic that will make extra property checks before adding to a return value.

您可以在此处查看有关阵列过滤的一些文献。如果您需要提供要删除的项目的首选项,您可以定义额外的参数和逻辑,以便在添加返回值之前进行额外的属性检查。

Hope that helps!

希望有所帮助!

#8


0  

Here is the typescript way

这是打字稿方式

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

And

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

#9


0  

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


0  

You can use lodash to remove duplicate objects:

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

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

Here 'id' is your unique identifier

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

#1


2  

You can use underscore for this:

您可以使用下划线:

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

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

#2


19  

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

usage (EcmaScript6 arrow functions makes it look better):

用法(EcmaScript6箭头功能使它看起来更好):

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

EDIT: edited snippet not to use property name, but to use a key selector function, so you can reach nested properties.

编辑:编辑片段不使用属性名称,但使用键选择器功能,因此您可以达到嵌套属性。

#3


8  

I don't think there's a built-in function in Angular, but it isn't hard to create one:

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

}

Usage:

用法:

removeDuplicates(arrayWithDuplicates, 'size');

Returns:

返回:

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

And

removeDuplicates(arrayWithDuplicates, 'color');

Returns:

返回:

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

#4


6  

Use Array.filter(), keeping track of values by using an Object as a hash, and filtering out any items whose value is already contained in the hash.

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

#5


1  

using lodash you can filter it out easily

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

the first parameter will be your array and second will be your field with duplicates

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

_.uniqBy(arrayWithDuplicates, 'color')

it will return an array with unique value

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

#6


1  

Simple solution although not the most performant:

简单的解决方案,虽然不是最高性能:

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


0  

Off the top of my head there is no one function that will do this for you as you are dealing with an array of objects and also there is no rule for which duplicate would be removed as duplicate.

在你的头顶上没有任何一个函数可以为你做这件事,因为你正在处理一组对象,并且没有规则将重复删除哪些副本。

In your example you remove the one with size: small but if you were to implement this using a loop you'd most likely include the first and exclude the last as you loop through your array.

在你的例子中,你删除了一个size:small但是如果你要使用循环实现它,你很可能包括第一个并在循环遍历数组时排除最后一个。

It may very well be worth taking a look at a library such as lodash and creating a function that uses a combination of it's API methods to get the desired behaviour you want.

看看像lodash这样的库并创建一个使用它的API方法组合来获得所需行为的函数可能是非常值得的。

Here is a possible solution you could use making use of basic Arrays and a filter expression to check whether a new item would be considered a duplicate before being attached to a return result.

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

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

You can check out some literature on Array filtering here If you need to provide a preference on which item to remove you could define extra parameters and logic that will make extra property checks before adding to a return value.

您可以在此处查看有关阵列过滤的一些文献。如果您需要提供要删除的项目的首选项,您可以定义额外的参数和逻辑,以便在添加返回值之前进行额外的属性检查。

Hope that helps!

希望有所帮助!

#8


0  

Here is the typescript way

这是打字稿方式

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

And

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

#9


0  

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


0  

You can use lodash to remove duplicate objects:

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

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

Here 'id' is your unique identifier

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