JavaScript сравнивает 2 массива и находит уникальные значения, используя пару ключ-значение в объекте

Я пишу функцию diff(arr1, arr2) для сравнения двух массивов и возврата нового массива со всеми элементами, не найденными в обоих исходных массивах.

Пример:

diff([1, 2, 3, 5], [1, 2, 3, 4, 5]) 
// [4]

diff([1, "calf", 3, "piglet"], [7, "filly"])
// [1, "calf", 3, "piglet", 7, "filly"]

Мое решение состоит в том, чтобы построить объект, используя уникальное значение в массиве в качестве ключа и частоту в качестве значения для этого ключа. Затем я собираю ключ, значение которого равно 1, в новый массив.

Проблема: я думаю, что тот факт, что ключ обрабатывается как строка в объекте, делает мое решение не очень элегантным, потому что мне нужно будет использовать Number() для преобразования «целочисленного» ключа из строки в число.

Вопрос: мой код работает, но есть ли у кого-нибудь лучшее решение для поиска уникальных значений после сравнения двух массивов?

Мой код:

function diff(arr1, arr2) {

  var newArr = arr1.concat(arr2);
  var dict = {};

  for (var i = 0; i < newArr.length; i++) {
    if (!dict[newArr[i]]) {
      dict[newArr[i]] = 1;
    }
    else {
      dict[newArr[i]]++;
    } 

  }

  var unique = [];

  for (var key in dict) {
    if (dict[key] === 1) {
      if (!Number(key)) {
        unique.push(key);
      }
      else {
        unique.push(Number(key));
      }
    }
  }
  return unique;
}

Спасибо за помощь =)


person Neong    schedule 30.10.2015    source источник
comment
Можете ли вы показать пример, для которого код не работает?   -  person thefourtheye    schedule 30.10.2015
comment
@thefourtheye мой код работает, но не очень элегантно, так как мне нужно преобразовать целочисленный ключ обратно в число.   -  person Neong    schedule 30.10.2015
comment
Никаких других вариантов. Если ваша среда поддерживает ES6, используйте Set.   -  person thefourtheye    schedule 30.10.2015
comment
Это не диф. Это симметричная разница в соответствии с этой страницей: en.wikipedia.org/wiki/Set_%28mathematics%29   -  person sectus    schedule 30.10.2015
comment
jsfiddle.net/wnLn3y4p Попробуйте это   -  person ANR Upgraded Version    schedule 30.10.2015


Ответы (4)


Вы можете реализовать функцию diff следующим образом, если можете использовать underscore.js.

function diff (arr1, arr2) {
  return _.difference(arr1, arr2).concat(_.difference(arr2, arr1));
}
person ntalbs    schedule 30.10.2015

Оставляя в стороне вопросы производительности, это можно записать так:

function complement(a1, a2) { return a1.filter(v => !a2.includes(v)); }
function union     (a1, a2) { return a1.concat(a2); }

function difference(a1, a2) { return union( complement(a1, a2), complement(a2, a1) ); }

Вам понадобится среда, поддерживающая Array#includes, или полифилл, или напишите сами:

function complement(a1, a2) { return a1.filter(v => a2.indexOf(v) === -1); }
person Community    schedule 30.10.2015
comment
Решение не работает для меня. Я проверил это в консоли FF 40. - person Alexander Elgin; 30.10.2015
comment
Исправлена ​​опечатка и добавлено примечание о includes. - person ; 30.10.2015

Вот чистое решение JS:

var diff = function(array1, array2) {
    var simmetricDifference = [];

    var getMissedItems = function(sourceArray, searchInArray) {
        sourceArray.forEach(function(item) {
            if((searchInArray.indexOf(item) === -1) && (simmetricDifference.indexOf(item) === -1)) {
                simmetricDifference.push(item);
            }
        });
    };

    getMissedItems(array1, array2);
    getMissedItems(array2, array1);

    return simmetricDifference;
};
person Alexander Elgin    schedule 30.10.2015
comment
Формальное определение симметричного различия заключается в том, что оно не удаляет повторяющиеся элементы в одном из массивов. - person ; 30.10.2015

вопрос на самом деле относится к функции симметричной разницы. Используйте _.xor.

person kornieff    schedule 30.10.2015
comment
Думаю, вам следует добавить _.xor не родной Javascript, а метод из одной из нескольких фреймворков/библиотек. - person Blindman67; 30.10.2015