Ответ 1
Вы можете использовать underscore для этого:
//by size:
var uSize = _.uniq(arrayWithDuplicates, function(p){ return p.size; });
//by custom.price;
var uPrice = _.uniq(arrayWithDuplicates, function(p){ return p.custom.price; });
У меня есть массив объектов, которые я хотел бы обрезать на основе определенной пары key:value
. Я хочу создать массив, который включает только один объект для этой конкретной пары key:value
. Не обязательно, какой объект дубликатов будет скопирован в новый массив.
Например, я хочу обрезать на основе свойства price
arrayWithDuplicates
, создав новый массив, который включает только одно из каждого значения:
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: свойство для фильтрации включено в другое свойство.
Вы можете использовать underscore для этого:
//by size:
var uSize = _.uniq(arrayWithDuplicates, function(p){ return p.size; });
//by custom.price;
var uPrice = _.uniq(arrayWithDuplicates, function(p){ return p.custom.price; });
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;
});
}
Использование (функции стрелок EcmaScript6 делают его лучше):
removeDuplicatesBy(x => x.custom.price, yourArrayWithDuplicates);
EDIT: отредактированный фрагмент не использовать имя свойства, но использовать функцию выбора ключа, чтобы вы могли достичь вложенных свойств.
Я не думаю, что есть встроенная функция в 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"
}
]
Используйте 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;
});
}
Простое решение, хотя и не самое результативное:
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')
он вернет массив с уникальным значением
В верхней части моей головы нет ни одной функции, которая будет делать это для вас, поскольку вы имеете дело с массивом объектов, а также нет правила, для которого дубликат будет удален как дубликат.
В вашем примере вы удаляете один с 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'));
Вы можете проверить литературу по фильтрации массива здесь Если вам нужно предоставить предпочтение, по которому удаляется элемент, вы можете определить дополнительные параметры и логику, которые будут выполнять дополнительные проверки свойств перед добавлением к возвращаемому значению.
Надеюсь, что это поможет!
Вот способ typescript
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
' - ваш уникальный идентификатор
Это просто еще одна "особенность", основанная на решении 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));
}