Подтвердить что ты не робот

Объединение двух коллекций с помощью Underscore.JS

Если у меня есть две коллекции:

c1 - [{a:1},{a:2},{a:3}]

и

c2 - [{a:1},{a:7},{a:8}]

какой самый быстрый способ добавить уникальные элементы из c2 в c1 с помощью Underscore.JS? Реальные числа в коллекциях будут 2K для c1 и 500 для c2, операция выполняется часто, поэтому должна быть выполнена!

Обновление 1. Я использую Underscore.JS в течение нескольких дней, я не мог найти способ добавить одну коллекцию в другую (я могу фильтровать c2 сам) - это что тривиально в Underscore.JS?

4b9b3361

Ответ 1

Следующее будет:

  • создать новый массив, содержащий все элементы c1 и c2. См. union.
  • из этого микса, создайте новый массив, содержащий только уникальные элементы. См. uniq.

Обратите внимание, что это будет работать, только если все ваши объекты имеют свойство a.

_.uniq(_.union(c1, c2), false, function(item, key, a){ return item.a; });

Вы можете найти другие варианты в этом вопросе.

Ответ 2

Попробуйте:

_.uniq(_.union(c1, c2), false, _.property('a'))

Подробнее:

  • _.union(*arrays)

    Вычисляет объединение переданных массивов.

  • _.property(key) (начиная с версии 1.6.0)

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

  • _.uniq(array, [isSorted], [iteratee])

    Производит дублируемую версию массива, используя === для проверки равенства объектов. Если вы заранее знаете, что массив отсортирован, передача true для isSorted будет выполнять гораздо более быстрый алгоритм. Если вы хотите вычислить уникальные элементы на основе преобразования, передайте функцию iteratee.

Ответ 3

В документации для функции uniq() указано, что она выполняется намного быстрее, если список сортируется. Также использование цепочечных вызовов может улучшить читаемость. Итак, вы можете сделать:

_.chain(c1).union(c2).sortBy("a").uniq(true, function(item){ return item.a; }).value();

Или, если вы предпочитаете unchained версию (которая на 11 символов короче, но менее читаема):

_.uniq(_.sortBy(_.union(c1,c2),"a"),true, function(item){ return item.a; });

В документации и примерах для uniq() не указывается, как работает функция обратного вызова. Алгоритм функции uniq() вызывает эту функцию для каждого элемента из обоих списков. Если результат этой функции одинаков, она удаляет этот элемент (при условии, что он дублируется).

union() фактически предотвращает дублирование при вызове массива. Мы также можем использовать этот факт:

_.map(_.union(_.pluck(c1,"a"),_.pluck(c2,"a")),function (item) {return {a:item};});

Вышеприведенное, как и первое преобразование списка объектов в простые массивы (pluck()), затем объединяет их с помощью union() и в конечном итоге использует map() для создания списка объектов.

Ссылка: uniq()

Ответ 4

Поскольку в обоих объектах существует огромное количество свойств, и этот алгоритм работает часто, лучше использовать основной Javascript вместо любой библиотеки:

//adds all new properties from the src to dst. If the property already exists, updates the number in dst. dst and src are objects
function extendNumberSet( dst, src ) {
    var allVals = [];
    for ( var i = 0; i < dst.length; i++ ) {
        allVals.push(dst[i].a);
    }
    for ( var i = 0; i < src.length; i++ ) {
        if ( allVals.indexOf( src[i].a ) === -1 ) {
            dst.push( src[i] );
        }
    }
}

здесь JSfiddle, чтобы проверить его.