Поиск симметричной разности / уникальных элементов в нескольких массивах в JavaScript

Привет, я изо всех сил, чтобы решить эту проблему. Как создать функцию javascript, которая принимает любое количество массивов в качестве аргументов, а затем возвращает массив элементов, которые появляются только в одном из массивов. Все элементы, которые появляются в нескольких массивах, удаляются. Не имея решения, подозреваю, что я не подхожу к нему правильно, тупик!

Изменить: другой вопрос адресов, устраняющих повторяющиеся значения в одном массиве, мне нужно сравнить х количество отдельных массивов и вернуть значения, которые не дублируются между массивами. Так ([5,6,7],[5,8,9]) возвращается [6,7,8,9].

function sym(args) {
  var ans = [];


  for(var i =0;i<arguments.length;i++){
    var tempArr = arguments[i].filter(function(el){
      var filtTrue = false;
       for(var j = 0;j<arguments.length;j++){
         if(Array.isArray(arguments[j]) && arguments[j] !== arguments[i]){
           if(arguments[j].indexOf(el) === -1){
             filtTrue = true;
              }}
        }
           return filtTrue;
          });
           ans = ans.concat(tempArr);
  }



    return ans;
  }

3 ответа

Решение

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

Вы не указали, что делать, если элемент появляется более одного раза в одном и том же массиве, но не в каком-либо другом массиве. Это первое решение не будет включать этот элемент (поскольку он обнаруживает дубликаты). Он может быть адаптирован (с немного большей сложностью), чтобы разрешить этот элемент, если это было проблемой (см. 2-й блок кода ниже для этой реализации).

function sym(/* pass one or more arrays here */) {
    var ans = [], cnts = {};

    //count all items in the array
    for (var i = 0; i < arguments.length; i++){
        arguments[i].forEach(function(item) {
            if (cnts.hasOwnProperty(item)) {
                // increase cnt
                ++cnts[item].cnt;
            } else {
                // initalize cnt and value
                cnts[item] = {cnt: 1, val: item};
            }
        });
    }
    for (var item in cnts) {
        if (cnts.hasOwnProperty(item) && cnts[item].cnt === 1) {
            ans.push(cnts[item].val);
        }
    }

    return ans;
}

Если вы хотите включить элементы, которые присутствуют более одного раза в одном массиве, но отсутствуют в любом другом массиве, то вы можете использовать эту немного более сложную адаптацию:

function sym(/* pass one or more arrays here */) {
    var ans = [], cnts = {}, currentMap;

    //count all items in the array
    for (var i = 0; i < arguments.length; i++){
        currentMap = {};
        arguments[i].forEach(function(item) {
            // if we haven't already counted this item in this array
            if (!currentMap.hasOwnProperty(item)) {
                if (cnts.hasOwnProperty(item)) {
                    // increase cnt
                    ++cnts[item].cnt;
                } else {
                    // initalize cnt and value
                    cnts[item] = {cnt: 1, val: item};
                }
            }
            // keep track of whethere we've already counted this item in this array
            currentMap[item] = true;
        });
    }
    // output all items that have a cnt of 1
    for (var item in cnts) {
        if (cnts.hasOwnProperty(item) && cnts[item].cnt === 1) {
            ans.push(cnts[item].val);
        }
    }

    return ans;
}

Рабочая демонстрация: http://jsfiddle.net/jfriend00/bete5k3n/

Я знаю, что это слишком поздно, но это еще один способ сделать это. Возможно, не самый строгий, но, безусловно, творческий. Метод Array.symmetricDifference() ожидает любое количество аргументов и возвращает симметричное различие этих аргументов.

Array.prototype.symmetricDifference = function() {
  var args = [];

  // copy arguments into a real array and get rid of duplicates with filter
  for(var i = 0; i < arguments.length; i++) {
    args[i] = arguments[i];
    args[i] = args[i].filter(function(item, pos, self) {
      return self.indexOf(item) == pos;
    });
  }
  var diff = args[0];

  // iterate through every arguments in args.
  // concatenate the first two arguments to form a new set.
  // now every number in this new set that was contained in both arguments
  // from before will be contained at least twice in this new set.
  for(var j = 1; j < args.length; j++) {
    //sort the new set so that duplicates are next to each other.
    diff = diff.concat(args[j]).sort();
    var index = 0;

    // now iterate through the new set and delete both duplicates if you
    // find any. Otherwise proceed to the next index.
    while(index < diff.length) {
      // if duplicate is found delete both, otherwise look at next index.
      diff[index] === diff[index + 1] ? diff.splice(index, 2) : index++;
    }
  }
  return diff;
};

Вы можете вызвать этот метод для любого массива или создать новый и вызвать его для этого, например, так:

// take any number of arrays
var a = [3, 3, 3, 2, 5];
var b = [2, 1, 5, 7];
var c = [3, 4, 6, 6];
var d = [1, 2, 3];
var e = [5, 3, 9, 8];
var f = [1];

// invoke the method on "solution" with any number of arguments
// and store it in solution.
var solution = solution.symmetricDifference(a,b,c,d,e,f);

console.log(solution); // [1, 2, 4, 5, 6, 7, 8, 9]

Надеюсь, это поможет!

Поиск уникальных предметов в нескольких массивах

function uniqueItemsInArrays(...args){
  let allItems = [];
  allItems = allItems.concat(...args)

  return allItems.filter(function(item, pos, self) {
         return self.indexOf(item) === pos && self.indexOf(item,pos+1) === -1;
  });
}

uniqueItemsInArrays( [1, 5, 1, 8, 1, 2],
                         [2, 2, 9, 3, 5],
                         [1, 4, 7, 6] );

Приведенный выше код использует параметры отдыха ES6 для доступа ко всем массивам, переданным в качестве аргументов. Затем, используя функцию concat(), я объединяю все отдельные массивы в один массив. Наконец, функция фильтра была использована для идентификации и возврата уникальных элементов из этого массива. Логика здесь состоит в том, чтобы найти первый индекс текущего элемента, и если больше нет вхождения из первого индекса, мы возвращаем этот элемент.

Другие вопросы по тегам