2016-03-04 3 views
1

У меня есть массивы, такие как следующие:Получить массив уникальных элементов из массивов объектов

files = [ 
     {name: 'Lorem', other: true}, 
     {name: 'Foo', other: true}, 
     {name: 'Bar', other: true} 
     ]; 


files = [ 
     {name: 'Lorem', other: true}, 
     {name: 'Xxxxx', other: true} 
     ]; 


files = [ 
     {name: 'Lorem', other: true}, 
     {name: 'Foo', other: true}, 
     {name: 'Epic', other: true}, 
     {name: 'Xxxxx', other: true} 
     ]; 

Я пытаюсь получить объединенный массив с уникальными элементами подчеркиванием, но он не работает. Вот мой код:

function getAllFiles(alldocs) { 
    var all = []; 

    _.each(alldocs, function(element) { 
    all = _.union(all, element.files); 
    }); 

    return all; 
} 

Но я получаю массив с повторяющимися элементами.

+2

см https://github.com/jashkenas/underscore/issues/2311 –

+1

Вы могли бы, вероятно, использовать http://underscorejs.org/#uniq также с 'union' –

+0

Растворы приведенные ниже, проверяют только свойство 'name', но, возможно, вы хотите различить свойства «name» и «other». Прокрутите массив и проверьте оба. Если это единственное значение, которое вы хотите проверить, вы можете сделать это с помощью карты и уменьшить однострочный. – MartijnK

ответ

2

Использование подчеркивание вы можете сделать это следующим образом:

files1 = [ 
     {name: 'Lorem', other: true}, 
     {name: 'Foo', other: true}, 
     {name: 'Bar', other: true} 
     ]; 


files2 = [ 
     {name: 'Lorem', other: true}, 
     {name: 'Xxxxx', other: true} 
     ]; 


files3 = [ 
     {name: 'Lorem', other: true}, 
     {name: 'Foo', other: true}, 
     {name: 'Epic', other: true}, 
     {name: 'Xxxxx', other: true} 
     ]; 
//append all json 
all = _.union(files1,files2, files3); 
//get unique by define function which returns name (deciding factor for unique) 
all = _.uniq(all, function(d){return d.name}); 
console.log(all);//prints the unique elements 

рабочий код here

1

Раствор в простом Javascrift временный объект и Array#forEach()

var files1 = [{ name: 'Lorem', other: true }, { name: 'Foo', other: true }, { name: 'Bar', other: true }], 
 
    files2 = [{ name: 'Lorem', other: true }, { name: 'Xxxxx', other: true }], 
 
    result = function (array) { 
 
     var o = {}, r = []; 
 
     array.forEach(function (a) { 
 
      if (!(a.name in o)) { 
 
       o[a.name] = a; 
 
       r.push(o[a.name]); 
 
      } 
 
     }); 
 
     return r; 
 
    }(files1.concat(files2)); 
 

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

0

Это происходит потому, что вы используете массивы объектов и Подчеркивание не знает, какой объект атрибута использовать при сравнении элементов (например, имя, другие), здесь чистый раствор:

files = _.chain(files).indexBy("name").values(); 
1

вы должны применить uniq метод после union са LL.

Проблема заключается в том, что uniq по умолчанию использует оператор === для проверки равенства элементов массива. Поэтому, если у вас есть массив объектов, каждый объект будет сравниваться с ссылкой, а не значением, что явно нежелательно. Эту проблему можно решить, поставив uniq с дополнительным параметром - функцией обратного вызова (iteratee), которая преобразует элемент массива в просто сравнимое значение. В вашем случае вы можете использовать метод JSON.stringify, который возвращает строковое представление объекта.

function getAllFiles(alldocs) { 
    var union = _.union.apply(null, alldocs.map(function(v) { 
     return v.files; 
    })); 
    return _.uniq(union, function(v) { 
     return JSON.stringify(v); 
    }); 
} 
var alldocs = [ 
    {files: [ 
     {name: 'Lorem', other: true}, 
     {name: 'Foo', other: true}, 
     {name: 'Bar', other: true} 
    ]}, 
    {files: [ 
     {name: 'Lorem', other: true}, 
     {name: 'Xxxxx', other: true} 
    ]}, 
    {files: [ 
     {name: 'Lorem', other: true}, 
     {name: 'Foo', other: true}, 
     {name: 'Epic', other: true}, 
     {name: 'Xxxxx', other: true} 
    ]} 
]; 
var result = getAllFiles(alldocs); 

Fiddle

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