2015-04-27 4 views
3

Учитывая массив объектов:Фильтр массив объектов для уникальных элементов

var arr = [ 
    {a: "foo", b: "bar", c: "baz" }, 
    {a: "foo", b: "bar", c: "qux" }, 
    {a: "foo", b: "bar", c: "baz" }, 
    {a: "foo", b: "bar", c: "qux" }, 
    {a: "bar", b: "foo", c: "qux" }, 
    {a: "bar", b: "qux", c: "foo" }, 
    {a: "bar", b: "foo", c: "qux" } 
]; 

Массив должен быть отфильтрован так только уникальные объекты остаются:

var arr = [ 
    {a: "foo", b: "bar", c: "baz" }, 
    {a: "foo", b: "bar", c: "qux" }, 
    {a: "bar", b: "foo", c: "qux" }, 
    {a: "bar", b: "qux", c: "foo" } 
]; 

Для массивов простых строк, я использую

arr.filter(function (value, index, self) { 
    return self.indexOf(value) === index; 
} 

но это не работает на объектах. Все свойства должны быть сопоставлены в моем случае. Думаю, нужно какое-то глубокое сравнение?

+0

Вы можете сцепить значение каждого объекта с разделитель и может добавить его к временному rray (Убедитесь, что индекс тот же). Затем вы можете сравнить его и удалить из основного массива. –

+0

http://jsfiddle.net/791gqw27/ – Andy

+0

Тот, кто хочет его снова открыть: не могли бы вы рассказать сообществу, почему вы думаете, что это не дубликат? – zerkms

ответ

-3

Используйте lodash! https://lodash.com/docs#uniq

Создает дубликат версию без массива, используя SameValueZero для сравнения равенства, в котором только первое вхождение каждого элемента хранится. Предоставление true для isSorted выполняет более быстрый алгоритм поиска для отсортированных массивов. Если предоставляется итерационная функция, она вызывается для каждого элемента массива для генерации критерия, по которому вычисляется уникальность. Итератор привязан к thisArg и вызывается с тремя аргументами: (значение, индекс, массив).

Включите его в HTML <script src="bower_components/lodash/lodash.js"></script>

Затем в контроллере.

var filteredArray = _.uniq(arr, function(item, key, a) { 
    return item.a; 
}); 

http://jsfiddle.net/8xp3o7b3/3/

+0

И «SameValueZero for equal» работает для объектов? – zerkms

+0

Добавил jsfiddle –

+2

Как насчет свойств 'b' и' c'? Что делает «а» особенным? Что делать, если у объекта нет 'a'? – zerkms

-2

Я использовал подход я уже упоминал в моем комментарии.

var arr = [ 
 
    {c: "baz", a: "foo", b: "bar" }, 
 
    {c: "qux", a: "foo", b: "bar" }, 
 
    {c: "baz", b: "bar", a: "foo" }, 
 
    {c: "qux", b: "bar", a: "foo" }, 
 
    {a: "bar", c: "qux", b: "foo" }, 
 
    {a: "bar", c: "foo", b: "qux" }, 
 
    {a: "bar", b: "foo", c: "qux" } 
 
]; 
 

 
var modified = arr.map(function (value) { 
 
    var result = []; 
 
    var keys = Object.keys(value).sort(); 
 

 
    for (var i = 0; i < keys.length; i++) { 
 
     result.push(value[keys[i]]); 
 
    } 
 
    return result.join(''); 
 
}); 
 

 
for (var i = (modified.length - 1); i >= 0; i--) { 
 
    if (modified.indexOf(modified[i]) !== i) { 
 
     arr.splice(i, 1); 
 
    } 
 
} 
 

 

 
alert(JSON.stringify(arr));

+0

Что делать, если некоторые значения уже есть ',' как часть? Решение подвержено ложным позитивным совпадениям. – zerkms

+0

@zerkms Обновить код, чтобы не использовать разделитель –

+0

«Обновить код, чтобы не использовать какой-либо разделитель» --- что это значит? Ваш код может давать ложные срабатывания. – zerkms

0

Если ваши объекты имеют одинаковые ключи, вы можете использовать lodash-х или _.findWhere функция Underscore в:

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

var arr = [ 
 
    {a: "foo", b: "bar", c: "baz" }, 
 
    {a: "foo", b: "bar", c: "qux" }, 
 
    {a: "foo", b: "bar", c: "baz" }, 
 
    {a: "foo", b: "bar", c: "qux" }, 
 
    {a: "bar", b: "foo", c: "qux" }, 
 
    {a: "bar", b: "qux", c: "foo" }, 
 
    {a: "bar", b: "foo", c: "qux" } 
 
]; 
 

 
function uniqueObjects(arr) { 
 
    var u = []; 
 
    arr.forEach(function(obj) { 
 
    if (!_.findWhere(u, obj)) { 
 
     u.push(obj); 
 
    } 
 
    }); 
 
    return u 
 
} 
 

 
document.getElementById('result').innerHTML = JSON.stringify(uniqueObjects(arr),null,2);
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.7.0/lodash.min.js"></script> 
 
<pre id='result'></pre>

Если нет, то глубокое сравнение может быть сделано с помощью _.matches в обоих направлениях:

var arr = [ 
 
    {a: "foo", b: "bar", c: "baz" }, 
 
    {a: "foo", b: "bar", c: "qux" }, 
 
    {a: "foo", b: "bar", c: "baz" }, 
 
    {a: "foo", b: "bar", c: "qux" }, 
 
    {a: "bar", b: "foo", c: "qux" }, 
 
    {a: "bar", b: "qux", c: "foo" }, 
 
    {a: "bar", b: "foo", c: "qux" }, 
 
    // Missing property 
 
    {a: "foo", b: "bar" }, 
 
    // Ordering 
 
    {a: "foo", c: "qux" }, 
 
    {c: "qux", a: "foo" } 
 
]; 
 

 
function uniqueObjects(arr) { 
 
    var u = []; 
 
    arr.forEach(function(obj) { 
 
    if (!u.filter(deepCompare(obj)).length) { 
 
     u.push(obj); 
 
    } 
 
    }); 
 
    return u; 
 
} 
 

 
function deepCompare(obj) { 
 
    return function(source) { 
 
    return _.matches(obj)(source) && _.matches(source)(obj); 
 
    }; 
 
} 
 

 
document.getElementById('result').innerHTML = JSON.stringify(uniqueObjects(arr),null,2);
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.7.0/lodash.min.js"></script> 
 
<pre id='result'></pre>

+0

'_.findWhere' не гарантирует равенства элементов, он просто проверяет предоставленные атрибуты. Например: '{a: 1}' будет найден как объект '{a: 1, b: 2}' – zerkms

+0

Спасибо, неверное предположение, что все объекты будут иметь все те же ключи. Обновлен мой ответ. – DTing

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