2015-08-27 1 views
16

У меня есть массив объектов, которые я хотел бы обрезать на основе определенной пары key:value. Я хочу создать массив, который включает только один объект для этой конкретной пары key:value. Не обязательно, какой объект дубликатов будет скопирован в новый массив.JavaScript: удалить дубликаты объектов, имеющих одно и то же значение свойства

Например, я хочу, чтобы урезать на основе 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 или Угловая функция, которая будет проходить через это и делать это?

EDIT: свойство фильтровать вложенно в другое свойство.

+0

возможно дубликат [Удалить дубликаты из массива объектов в JavaScript] (http://stackoverflow.com/questions/2218999/remove-duplicates-from-an-array-of-objects-in-javascript) –

+0

вы ищете что-то вроде функции _.map или _.pluck в подчеркивании е? http://underscorejs.org/#pluck – ncubica

ответ

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

Он был изменен на _.uniqBy и он получает уникальное имя свойства. _.uniqBy ([{'x': 1}, {'x': 2}, {'x': 1}], 'x'); // => [{'x': 1}, {'x': 2}] – natansun

7

Я не думаю, что есть встроенная функция в Угловом, но это не так трудно создать:

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

Возвращает:

[ 
    { 
     "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" 
    } 
] 
17
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: редактировать фрагмент не использовать имя свойства, но использовать функцию выбора ключа, чтобы вы могли достичь вложенных свойств.

+0

Спасибо! Это определенно сработало, но я только что отредактировал свой вопрос, чтобы подумать, что это необходимо для фильтрации на вложенных свойствах (массивная промаха на моем конце). Может ли ваша функция справиться с этим? –

+0

отредактировал мой ответ –

+0

Спасибо, хороший ответ, но, очевидно, если вы используете ES6, вы можете столкнуться с проблемами в старых браузерах без какой-либо прокладки или полиполя (что не возможно для оператора стрелок, насколько я знаю, поскольку это синтаксическая ошибка). Чтобы заставить его работать с антикварными браузерами, например IE11, просто используйте функцию: 'removeDuplicatesBy (function (x) {return x.custom.price;}, yourArrayWithDuplicates);' – nothingisnecessary

5

Используйте 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; 
    }); 
} 
+0

большое вам спасибо, это очень меня спасло !!! – blackend

0

Off верхней части моей головы нет одна функция, которая будет делать это для вас, как вы имеете дело с массивом объектов, а также нет никакого правила, для которых дубликат будет удален в двух экземплярах.

В вашем примере вы удаляете один из 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 Если вам необходимо предоставить предпочтение, на котором элемент для удаления можно определить дополнительные параметры и логику, которые сделают дополнительные проверки свойств перед добавлением в качестве возвращаемого значения.

Надеюсь, что это поможет!

1

Простое решение, хотя и не самый производительный:

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

с помощью lodash вы можете отфильтровать его легко первым параметром будет

ваш массив и второй будет вашим полем с дубликатами

_.uniqBy(arrayWithDuplicates, 'color') 

он возвращает массив с уникальным значением

0

Вот машинопись путь

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