Как получить разницу между двумя массивами в Javascript?

Прочитайте его в потоке, создайте растровое изображение, закройте поток.

606
задан Flip 10 October 2017 в 15:38
поделиться

17 ответов

Я предполагаю, что вы сравниваете обычный массив. Если нет, вам нужно заменить цикл for на for .. in loop.

 function arr_diff (a1, a2) {var a = [], diff = [ ]; for (var i = 0; i 

Лучшее решение, если вам не важна обратная совместимость, - использовать фильтр. Но все же это решение работает.

191
ответ дан 22 November 2019 в 21:47
поделиться

Версия CoffeeScript:

diff = (val for val in array1 when val not in array2)
1
ответ дан m.e.conroy 10 October 2017 в 15:38
поделиться
var result = [];
var arr1 = [1,2,3,4];
var arr2 = [2,3];
arr1.forEach(function(el, idx) {
    function unEqual(element, index, array) {
        var a = el;
        return (element!=a);
    }
    if (arr2.every(unEqual)) {
        result.push(el);
    };
});
alert(result);
0
ответ дан fog 10 October 2017 в 15:38
поделиться
function diff(arr1, arr2) {
  var filteredArr1 = arr1.filter(function(ele) {
    return arr2.indexOf(ele) == -1;
  });

  var filteredArr2 = arr2.filter(function(ele) {
    return arr1.indexOf(ele) == -1;
  });
  return filteredArr1.concat(filteredArr2);
}

diff([1, "calf", 3, "piglet"], [1, "calf", 3, 4]); // Log ["piglet",4]
2
ответ дан huy-tran 10 October 2017 в 15:38
поделиться
function diff(a1, a2) {
  return a1.concat(a2).filter(function(val, index, arr){
    return arr.indexOf(val) === arr.lastIndexOf(val);
  });
}

Объединение обоих массивов, уникальные значения появятся только один раз, поэтому indexOf () будет таким же, как lastIndexOf ().

29
ответ дан pdbrito 10 October 2017 в 15:38
поделиться

Используя http://phrogz.net/JS/ArraySetMath.js , вы можете:

var array1 = ["test1", "test2","test3", "test4"];
var array2 = ["test1", "test2","test3","test4", "test5", "test6"];

var array3 = array2.subtract( array1 );
// ["test5", "test6"]

var array4 = array1.exclusion( array2 );
// ["test5", "test6"]
4
ответ дан Phrogz 10 October 2017 в 15:38
поделиться

Аналогично решению Яна Грейнджера (но в машинописном тексте):

function findDiffs(arrayOne: string[], arrayTwo: string[]) {

    let onlyInArrayOne = []
    let onlyInArrayTwo = []
    let share = []
    let [arrayOneCopy, arrayTwoCopy] = [[...arrayOne], [...arrayTwo]]

    arrayOneCopy.sort(); arrayTwoCopy.sort()

    while (arrayOneCopy.length !== 0 && arrayTwoCopy.length !== 0) {
        if (arrayOneCopy[0] == arrayTwoCopy[0]) {
            share.push(arrayOneCopy[0])
            arrayOneCopy.splice(0, 1)
            arrayTwoCopy.splice(0, 1)
        }
        if (arrayOneCopy[0] < arrayTwoCopy[0]) {
            onlyInArrayOne.push(arrayOneCopy[0])
            arrayOneCopy.splice(0, 1)
        }
        if (arrayOneCopy[0] > arrayTwoCopy[0]) {
            onlyInArrayTwo.push(arrayTwoCopy[0])
            arrayTwoCopy.splice(0, 1)
        }
    }
    onlyInArrayTwo = onlyInArrayTwo.concat(arrayTwoCopy)
    onlyInArrayOne = onlyInArrayOne.concat(arrayOneCopy)

    return {
        onlyInArrayOne,
        onlyInArrayTwo,
        share,
        diff: onlyInArrayOne.concat(onlyInArrayTwo)
    }
}

// arrayOne: [ 'a', 'b', 'c', 'm', 'y' ] 
// arrayTwo: [ 'c', 'b', 'f', 'h' ]
//
// Results: 
// { 
//    onlyInArrayOne: [ 'a', 'm', 'y' ],
//    onlyInArrayTwo: [ 'f', 'h' ],
//    share: [ 'b', 'c' ],
//    diff: [ 'a', 'm', 'y', 'f', 'h' ] 
// }
1
ответ дан Ardeshir Valipoor 10 October 2017 в 15:38
поделиться

Выбранный ответ только наполовину прав. Вы должны сравнить массивы в обоих направлениях, чтобы получить полный ответ.

const ids_exist = [
   '1234',
   '5678',
   'abcd',
]

const ids_new = [
  '1234',
  '5678',
  'efjk',
  '9999',
]

function __uniq_Filter (__array_1, __array_2) {
  const one_not_in_two = __array_1.filter(function (obj) {
    return __array_2.indexOf(obj) == -1
  })
  const two_not_in_one = __array_2.filter(function (obj) {
    return __array_1.indexOf(obj) == -1
  })
  return one_not_in_two.concat(two_not_in_one)
}

let uniq_filter = __uniq_Filter(ids_exist, ids_new)

console.log('uniq_filter', uniq_filter) // => [ 'abcd', 'efjk', '9999' ]
0
ответ дан Flavio 10 October 2017 в 15:38
поделиться
var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];
var diff = [];
for (var i in a2) {
   var found = false;
   for (var j in a1) {
      if (a2[i] === a1[j]) found = true;
   }
   if (found === false) diff.push(a2[i]);
}

Это просто. Могут также использовать с объектами, проверяя одно свойство объекта. Как,

if (a2[i].id === a1[j].id) found = true;
2
ответ дан Фарид Джафаров 10 October 2017 в 15:38
поделиться

Как насчет этого:

Array.prototype.contains = function(needle){
  for (var i=0; i<this.length; i++)
    if (this[i] == needle) return true;

  return false;
} 

Array.prototype.diff = function(compare) {
    return this.filter(function(elem) {return !compare.contains(elem);})
}

var a = new Array(1,4,7, 9);
var b = new Array(4, 8, 7);
alert(a.diff(b));

Таким образом, вы можете сделать array1.diff(array2), чтобы получить их разницу (хотя ужасная сложность времени для алгоритма - O (array1.length x array2.length) Я считаю, )

6
ответ дан Cat 10 October 2017 в 15:38
поделиться

Просто подумать ... ради вызова ;-) будет ли это работать ... (для базовых массивов строк, чисел и т. Д.) Нет вложенных массивов

function diffArrays(arr1, arr2, returnUnion){
  var ret = [];
  var test = {};
  var bigArray, smallArray, key;
  if(arr1.length >= arr2.length){
    bigArray = arr1;
    smallArray = arr2;
  } else {
    bigArray = arr2;
    smallArray = arr1;
  }
  for(var i=0;i<bigArray.length;i++){
    key = bigArray[i];
    test[key] = true;
  }
  if(!returnUnion){
    //diffing
    for(var i=0;i<smallArray.length;i++){
      key = smallArray[i];
      if(!test[key]){
        test[key] = null;
      }
    }
  } else {
    //union
    for(var i=0;i<smallArray.length;i++){
      key = smallArray[i];
      if(!test[key]){
        test[key] = true;
      }
    }
  }
  for(var i in test){
    ret.push(i);
  }
  return ret;
}

array1 = "test1", "test2","test3", "test4", "test7"
array2 = "test1", "test2","test3","test4", "test5", "test6"
diffArray = diffArrays(array1, array2);
//returns ["test5","test6","test7"]

diffArray = diffArrays(array1, array2, true);
//returns ["test1", "test2","test3","test4", "test5", "test6","test7"]

Обратите внимание на сортировку скорее всего, будет не так, как указано выше ... но при желании вызовите .sort () для массива, чтобы отсортировать его.

2
ответ дан scunliffe 10 October 2017 в 15:38
поделиться

Чтобы получить симметричную разность , необходимо сравнить массивы обоими способами (или во всех случаях в случае нескольких массивов)

enter image description here

<час>

ES7 (ECMAScript 2016)

// diff between just two arrays:
function arrayDiff(a, b) {
    return [
        ...a.filter(x => !b.includes(x)),
        ...b.filter(x => !a.includes(x))
    ];
}

// diff between multiple arrays:
function arrayDiff(...arrays) {
    return [].concat(...arrays.map( (arr, i) => {
        const others = arrays.slice(0);
        others.splice(i, 1);
        const unique = [...new Set([].concat(...others))];
        return arr.filter(x => !unique.includes(x));
    }));
}
<час>

ES6 (ECMAScript 2015)

// diff between just two arrays:
function arrayDiff(a, b) {
    return [
        ...a.filter(x => b.indexOf(x) === -1),
        ...b.filter(x => a.indexOf(x) === -1)
    ];
}

// diff between multiple arrays:
function arrayDiff(...arrays) {
    return [].concat(...arrays.map( (arr, i) => {
        const others = arrays.slice(0);
        others.splice(i, 1);
        const unique = [...new Set([].concat(...others))];
        return arr.filter(x => unique.indexOf(x) === -1);
    }));
}
<час>

ES5 (ECMAScript 5.1 )

// diff between just two arrays:
function arrayDiff(a, b) {
    var arrays = Array.prototype.slice.call(arguments);
    var diff = [];

    arrays.forEach(function(arr, i) {
        var other = i === 1 ? a : b;
        arr.forEach(function(x) {
            if (other.indexOf(x) === -1) {
                diff.push(x);
            }
        });
    })

    return diff;
}

// diff between multiple arrays:
function arrayDiff() {
    var arrays = Array.prototype.slice.call(arguments);
    var diff = [];

    arrays.forEach(function(arr, i) {
        var others = arrays.slice(0);
        others.splice(i, 1);
        var otherValues = Array.prototype.concat.apply([], others);
        var unique = otherValues.filter(function (x, j) { 
            return otherValues.indexOf(x) === j; 
        });
        diff = diff.concat(arr.filter(x => unique.indexOf(x) === -1));
    });
    return diff;
}

Пример:

// diff between two arrays:
const a = ['a', 'd', 'e'];
const b = ['a', 'b', 'c', 'd'];
arrayDiff(a, b); // (3) ["e", "b", "c"]

// diff between multiple arrays
const a = ['b', 'c', 'd', 'e', 'g'];
const b = ['a', 'b'];
const c = ['a', 'e', 'f'];
arrayDiff(a, b, c); // (4) ["c", "d", "g", "f"]

Разница между массивами объектов

function arrayDiffByKey(key, ...arrays) {
    return [].concat(...arrays.map( (arr, i) => {
        const others = arrays.slice(0);
        others.splice(i, 1);
        const unique = [...new Set([].concat(...others))];
        return arr.filter( x =>
            !unique.some(y => x[key] === y[key])
        );
    }));
}

Пример:

const a = [{k:1}, {k:2}, {k:3}];
const b = [{k:1}, {k:4}, {k:5}, {k:6}];
const c = [{k:3}, {k:5}, {k:7}];
arrayDiffByKey('k', a, b, c); // (4) [{k:2}, {k:4}, {k:6}, {k:7}]
39
ответ дан Luca Borrione 10 October 2017 в 15:38
поделиться

Функциональный подход с ES2015

Вычисление difference между двумя массивами является одной из операций Set. Термин уже указывает, что для увеличения скорости поиска следует использовать собственный тип Set. В любом случае, при вычислении разницы между двумя наборами есть три перестановки:

[+left difference] [-intersection] [-right difference]
[-left difference] [-intersection] [+right difference]
[+left difference] [-intersection] [+right difference]

Вот функциональное решение, которое отражает эти перестановки.

Слева difference:

// small, reusable auxiliary functions

const apply = f => x => f(x);
const flip = f => y => x => f(x) (y);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));


// left difference

const differencel = xs => ys => {
  const zs = createSet(ys);
  return filter(x => zs.has(x)
     ? false
     : true
  ) (xs);
};


// mock data

const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,3,6,7,8,9];


// run the computation

console.log( differencel(xs) (ys) );

Справа difference:

differencer является тривиальный. Это просто differencel с перевернутыми аргументами. Для удобства вы можете написать функцию: const differencer = flip(differencel). Вот и все!

Симметричный difference:

Теперь, когда у нас есть левый и правый, реализация симметричного difference также становится тривиальной:

// small, reusable auxiliary functions

const apply = f => x => f(x);
const flip = f => y => x => f(x) (y);
const concat = y => xs => xs.concat(y);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));


// left difference

const differencel = xs => ys => {
  const zs = createSet(ys);
  return filter(x => zs.has(x)
     ? false
     : true
  ) (xs);
};


// symmetric difference

const difference = ys => xs =>
 concat(differencel(xs) (ys)) (flip(differencel) (xs) (ys));

// mock data

const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,3,6,7,8,9];


// run the computation

console.log( difference(xs) (ys) );

Думаю, этот пример является хорошей отправной точкой для получения впечатления о том, что означает функциональное программирование:

Программирование с использованием строительных блоков, которые могут быть соединены вместе разными способами.

11
ответ дан 10 October 2017 в 15:38
поделиться

Это было вдохновлено принятым ответом Thinker, но ответ Thinker, кажется, предполагает, что массивы являются наборами. Он распадается, если массивы [ "1", "2" ] и [ "1", "1", "2", "2" ]

Разница между этими массивами составляет [ "1", "2" ]. Следующее решение - O (n * n), поэтому оно не идеальное, но если у вас большие массивы, оно также имеет преимущество в памяти по сравнению с решением Thinker.

Если вы имеете дело с сетами в первую очередь, решение Thinker определенно лучше. Если у вас есть более новая версия Javascript с доступом к фильтрам, вы должны также использовать их. Это только для тех, кто не имеет дело с наборами и использует более старую версию JavaScript (по какой-либо причине) ...

if (!Array.prototype.diff) { 
    Array.prototype.diff = function (array) {
        // if the other array is a falsy value, return a copy of this array
        if ((!array) || (!Array.prototype.isPrototypeOf(array))) { 
            return this.slice(0);
        }

        var diff = [];
        var original = this.slice(0);

        for(var i=0; i < array.length; ++i) {
            var index = original.indexOf(array[i]);
            if (index > -1) { 
                original.splice(index, 1);
            } else { 
                diff.push(array[i]);
            }
        }

        for (var i=0; i < original.length; ++i) {
            diff.push(original[i]);
        }
        return diff;
    }
}   
2
ответ дан redusek 10 October 2017 в 15:38
поделиться

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

Убедитесь, что он применим к вашему случаю, если он не допускает дубликатов.

var a = new JS.Set([1,2,3,4,5,6,7,8,9]);
var b = new JS.Set([2,4,6,8]);

a.difference(b)
// -> Set{1,3,5,7,9}
36
ответ дан 22 November 2019 в 21:47
поделиться

Мне нужна была похожая функция, которая принимала бы старый массив и новый массив и давала бы мне массив добавленных элементов и массив удаленных элементов, и я хотел, чтобы она была эффективной (поэтому никаких .contains!).

Вы можете поиграть с предложенным мной решением здесь: http://jsbin.com/osewu3/12.

Может ли кто-нибудь увидеть какие-либо проблемы/улучшения в этом алгоритме? Спасибо!

Листинг кода:

function diff(o, n) {
  // deal with empty lists
  if (o == undefined) o = [];
  if (n == undefined) n = [];

  // sort both arrays (or this won't work)
  o.sort(); n.sort();

  // don't compare if either list is empty
  if (o.length == 0 || n.length == 0) return {added: n, removed: o};

  // declare temporary variables
  var op = 0; var np = 0;
  var a = []; var r = [];

  // compare arrays and add to add or remove lists
  while (op < o.length && np < n.length) {
      if (o[op] < n[np]) {
          // push to diff?
          r.push(o[op]);
          op++;
      }
      else if (o[op] > n[np]) {
          // push to diff?
          a.push(n[np]);
          np++;
      }
      else {
          op++;np++;
      }
  }

  // add remaining items
  if( np < n.length )
    a = a.concat(n.slice(np, n.length));
  if( op < o.length )
    r = r.concat(o.slice(op, o.length));

  return {added: a, removed: r}; 
}
2
ответ дан 22 November 2019 в 21:47
поделиться

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

let iterator = arrayA.values()
let result = []
for (entryA of iterator) {
    if (!arrayB.includes(entryA)) {
        result.push(entryA)
    } else {
        arrayB.splice(arrayB.indexOf(entryA), 1) 
    }
}

result.push(...arrayB)
return result

0
ответ дан 22 November 2019 в 21:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: