2016-03-16 3 views
9

У меня есть массив объектовУдалить дубликаты в массив объектов Javascript

list = [{x:1,y:2}, {x:3,y:4}, {x:5,y:6}, {x:1,y:2}] 

И Я ищу эффективный способ (если это возможно O(log(n))), чтобы удалить дубликаты и в конечном итоге с

list = [{x:1,y:2}, {x:3,y:4}, {x:5,y:6}] 

Я пробовал _.uniq или даже _.contains, но не смог найти подходящее решение.

Спасибо!

Редактировать: Вопрос был идентифицирован как дубликат другого. Я видел этот вопрос до публикации, но он не ответил на мой вопрос, так как это массив объектов (а не 2-мерный массив, спасибо Аарону), или, по крайней мере, решения по другому вопросу в моем случае не работали.

+1

Возможный дубликат [Удалить дубликаты из массива JavaScript] (http://stackoverflow.com/questions/9229645/remove-duplicates-from-javascript-array) – Rajesh

+1

Примечание что это не двумерный массив, а массив массивов. – Aaron

ответ

9

Ванильный JS версии:

function dedupe(arr) { 
    return arr.reduce(function (p, c) { 

    // create an identifying id from the object values 
    var id = [c.x, c.y].join('|'); 

    // if the id is not found in the temp array 
    // add the object to the output array 
    // and add the key to the temp array 
    if (p.temp.indexOf(id) === -1) { 
     p.out.push(c); 
     p.temp.push(id); 
    } 
    return p; 

    // return the deduped array 
    }, { temp: [], out: [] }).out; 
} 

dedupe(list); 

DEMO

1

Ниже будет работать:

var a = [{x:1,y:2}, {x:3,y:4}, {x:5,y:6}, {x:1,y:2}]; 

var b = _.uniq(a, function(v) { 
    return v.x && v.y; 
}) 

console.log(b); // [ { x: 1, y: 2 }, { x: 3, y: 4 }, { x: 5, y: 6 } ] 
+1

Спасибо! Работает для меня, это быстрее, чем решение Энди? – kwn

+0

Я понятия не имею. Это меньше кода для написания, и подчеркивание, кажется, включено в любой путь ... @kwn – baao

+2

Если вы не имеете дело с 10 из 1000 элементов, производительность не должна быть проблемой. Думаю, вам нужно взвесить стоимость загрузки отдельной библиотеки (если lodash уже не в вашем стеке) или просто используя немного более многословную функцию ванили. – Andy

4

Фильтр массива после проверки, если уже в временый объекта в O (N).

var list = [{ x: 1, y: 2 }, { x: 3, y: 4 }, { x: 5, y: 6 }, { x: 1, y: 2 }], 
 
    filtered = function (array) { 
 
     var o = {}; 
 
     return array.filter(function (a) { 
 
      var k = a.x + '|' + a.y; 
 
      if (!o[k]) { 
 
       o[k] = true; 
 
       return true; 
 
      } 
 
     }); 
 
    }(list); 
 

 
document.write('<pre>' + JSON.stringify(filtered, 0, 4) + '</pre>');

14

Обычная Javascript (ES2015), используя Set

var list = [{ x: 1, y: 2 }, { x: 3, y: 4 }, { x: 5, y: 6 }, { x: 1, y: 2 }]; 
 

 
var uniq = new Set(list.map(e => JSON.stringify(e))); 
 

 
var res = Array.from(uniq).map(e => JSON.parse(e)); 
 

 
document.write(JSON.stringify(res));

+0

Он также работает в Angular 2. thanx – gnganpath

+2

'stringify' и' parse' не выглядят как наиболее эффективный способ достичь этого. – calbertts

+2

Вы не должны использовать var при написании кода в ES2015! –

2

Я хотел бы использовать комбинацию Arrayr.prototype.reduce и Arrayr.prototype.some методов с оператором распространения.

1. Явное решение. На основе полного знания объекта массива.

list = list.reduce((r, i) => 
    !r.some(j => i.x === j.x && i.y === j.y) ? [...r, i] : r 
, []) 

Здесь мы имеем строгое ограничение по сравнению структуры объектов: {x: N, y: M}.

2. Общий раствор, JSON.stringify(). У сравниваемых объектов может быть любое количество любых свойств.

list = list.reduce((r, i) => 
    !r.some(j => JSON.stringify(i) === JSON.stringify(j)) ? [...r, i] : r 
, []) 

Этот подход имеет ограничение на заказ свойства, поэтому [{x:1, y:2}, {y:2, x:1}] не будут фильтроваться.

3. Общий раствор, Object.keys(). Приказ не имеет значения.

list = list.reduce((r, i) => 
    !r.some(j => !Object.keys(i).some(k => i[k] !== j[k])) ? [...r, i] : r 
, []) 

Этот подход имеет другое ограничение: объекты сравнения должны иметь одинаковый список ключей. Таким образом, [{x:1, y:2}, {x:1}] будет отфильтрован, несмотря на очевидную разницу.

4. Родовой раствор, Object.keys() + .length.

list = list.reduce((r, i) => 
    !r.some(j => Object.keys(i).length === Object.keys(j).length 
    && !Object.keys(i).some(k => i[k] !== j[k])) ? [...r, i] : r 
, []) 

С последними объектами подхода сравниваются количество ключей, самих ключей и значений ключей.

Я создал Plunker, чтобы поиграть с ним.

9

Попробуйте использовать следующее:

list = list.filter((elem, index, self) => self.findIndex(
    (t) => {return (t.x === elem.x && t.y === elem.y)}) === index) 
+0

@Koby Спасибо за редактирование –

+0

Это прекрасно. Спасибо –

+0

Только вопрос, не можете ли вы просто использовать 'Object.is()' для сравнения вашего фильтра? https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is – JaeGeeTee

Смежные вопросы