Как сравнить массивы в JavaScript?

992

Я хотел бы сравнить два массива ... в идеале, эффективно. Ничего особенного, только trueесли они идентичны, а falseесли нет. Не удивительно, что оператор сравнения не работает.

var a1 = [1,2,3];
var a2 = [1,2,3];
console.log(a1==a2);    // Returns false
console.log(JSON.stringify(a1)==JSON.stringify(a2));    // Returns true

JSON кодирует каждый массив, но есть ли более быстрый или «лучший» способ простого сравнения массивов без необходимости перебирать каждое значение?

Джулиан Х. Лэм
источник
5
Вы могли бы сначала сравнить их длину, и если они равны каждому значению.
TJHeuvel
56
Что делает два массива равными для вас? Те же элементы? Одинаковый порядок элементов? Кодирование в формате JSON работает только до тех пор, пока элемент массива можно сериализовать в JSON. Если массив может содержать объекты, насколько глубоко вы пойдете? Когда два объекта "равны"?
Феликс Клинг
48
@FelixKling, определение «равенства», безусловно, является тонкой темой, но для людей, переходящих на JavaScript из языков более высокого уровня, нет оправдания такой глупости, как ([] == []) == false.
Алекс Д
4
@AlexD похоже, что массивы используют равенство ссылок, чего вы и ожидали. Было бы ужасно, если бы ты не смог этого сделать
JonnyRaa
3
@AlexD Я немного не могу придумать язык, где этого не происходит. В C ++ вы бы сравнивали два указателя - false. В Java вы делаете то же самое, что и в JavaScript. В PHP что-то закулисное зацикливается в массивах - вы называете PHP языком высшего уровня?
Томаш Зато - Восстановить Монику

Ответы:

877

Чтобы сравнить массивы, просмотрите их и сравните каждое значение:

Сравнение массивов:

// Warn if overriding existing method
if(Array.prototype.equals)
    console.warn("Overriding existing Array.prototype.equals. Possible causes: New API defines the method, there's a framework conflict or you've got double inclusions in your code.");
// attach the .equals method to Array's prototype to call it on any array
Array.prototype.equals = function (array) {
    // if the other array is a falsy value, return
    if (!array)
        return false;

    // compare lengths - can save a lot of time 
    if (this.length != array.length)
        return false;

    for (var i = 0, l=this.length; i < l; i++) {
        // Check if we have nested arrays
        if (this[i] instanceof Array && array[i] instanceof Array) {
            // recurse into the nested arrays
            if (!this[i].equals(array[i]))
                return false;       
        }           
        else if (this[i] != array[i]) { 
            // Warning - two different object instances will never be equal: {x:20} != {x:20}
            return false;   
        }           
    }       
    return true;
}
// Hide method from for-in loops
Object.defineProperty(Array.prototype, "equals", {enumerable: false});

Применение:

[1, 2, [3, 4]].equals([1, 2, [3, 2]]) === false;
[1, "2,3"].equals([1, 2, 3]) === false;
[1, 2, [3, 4]].equals([1, 2, [3, 4]]) === true;
[1, 2, 1, 2].equals([1, 2, 1, 2]) === true;

Вы можете сказать: « Но сравнивать строки гораздо быстрее - никаких циклов ... », тогда вы должны заметить, что есть циклы ARE. Первый рекурсивный цикл, который преобразует массив в строку, а второй, который сравнивает две строки. Так что этот метод быстрее, чем использование строки .

Я считаю, что большие объемы данных всегда должны храниться в массивах, а не в объектах. Однако, если вы используете объекты, их тоже можно частично сравнить.
Вот как:

Сравнение объектов:

Я уже говорил выше, что два экземпляра объекта никогда не будут равны, даже если они на данный момент содержат одинаковые данные:

({a:1, foo:"bar", numberOfTheBeast: 666}) == ({a:1, foo:"bar", numberOfTheBeast: 666})  //false

Это имеет причину, поскольку, например, в объектах могут быть частные переменные.

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

Object.prototype.equals = function(object2) {
    //For the first loop, we only check for types
    for (propName in this) {
        //Check for inherited methods and properties - like .equals itself
        //https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
        //Return false if the return value is different
        if (this.hasOwnProperty(propName) != object2.hasOwnProperty(propName)) {
            return false;
        }
        //Check instance type
        else if (typeof this[propName] != typeof object2[propName]) {
            //Different types => not equal
            return false;
        }
    }
    //Now a deeper check using other objects property names
    for(propName in object2) {
        //We must check instances anyway, there may be a property that only exists in object2
            //I wonder, if remembering the checked values from the first loop would be faster or not 
        if (this.hasOwnProperty(propName) != object2.hasOwnProperty(propName)) {
            return false;
        }
        else if (typeof this[propName] != typeof object2[propName]) {
            return false;
        }
        //If the property is inherited, do not check any more (it must be equa if both objects inherit it)
        if(!this.hasOwnProperty(propName))
          continue;

        //Now the detail check and recursion

        //This returns the script back to the array comparing
        /**REQUIRES Array.equals**/
        if (this[propName] instanceof Array && object2[propName] instanceof Array) {
                   // recurse into the nested arrays
           if (!this[propName].equals(object2[propName]))
                        return false;
        }
        else if (this[propName] instanceof Object && object2[propName] instanceof Object) {
                   // recurse into another objects
                   //console.log("Recursing to compare ", this[propName],"with",object2[propName], " both named \""+propName+"\"");
           if (!this[propName].equals(object2[propName]))
                        return false;
        }
        //Normal value comparison for strings and numbers
        else if(this[propName] != object2[propName]) {
           return false;
        }
    }
    //If everything passed, let's say YES
    return true;
}  

Однако помните, что этот служит для сравнения данных, подобных JSON, а не экземпляров классов и прочего. Если вы хотите сравнить более сложные объекты, посмотрите на этот ответ, и это сверхдлинная функция .
Чтобы сделать это с Array.equalsвами, вы должны немного отредактировать оригинальную функцию:

...
    // Check if we have nested arrays
    if (this[i] instanceof Array && array[i] instanceof Array) {
        // recurse into the nested arrays
        if (!this[i].equals(array[i]))
            return false;
    }
    /**REQUIRES OBJECT COMPARE**/
    else if (this[i] instanceof Object && array[i] instanceof Object) {
        // recurse into another objects
        //console.log("Recursing to compare ", this[propName],"with",object2[propName], " both named \""+propName+"\"");
        if (!this[i].equals(array[i]))
            return false;
        }
    else if (this[i] != array[i]) {
...

Я сделал небольшой тестовый инструмент для обеих функций .

Бонус: вложенные массивы с indexOfиcontains

Сэми Бенчериф подготовил полезные функции для случая, когда вы ищете конкретный объект во вложенных массивах, которые доступны здесь: https://jsfiddle.net/SamyBencherif/8352y6yw/

Томаш Зато - Восстановить Монику
источник
27
Если вы хотите делать строгие сравнения, используйте this[i] !== array[i]вместо !=.
Тим С.
38
Ваш метод должен быть вызван equalsвместо compare. По крайней мере, в .NET метод сравнения обычно возвращает подписанное int, указывающее, какой объект больше другого. Смотрите: Сравнить .
Оливер
15
Не только это правильный способ сделать это, но и значительно более эффективный. Вот быстрый скрипт jsperf, который я подготовил для всех методов, предложенных в этом вопросе. jsperf.com/comparing-arrays2
Tolga E
96
Изменение прототипа встроенного типа определенно не является правильным способом
Джаспер
31
Кроме того, речь идет не о том, легко ли переписать, а о том, что в ответе не следует рекомендовать что-то, что считается плохой практикой ( developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/… ) и следует определенно не делайте этого ниже заголовка «Правильный путь»
Джаспер
386

Хотя это работает только для скалярных массивов (см. Примечание ниже), оно короткое:

array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]})

Rr, в ECMAScript 6 / CoffeeScript / TypeScript с функциями стрелки:

array1.length === array2.length && array1.every((value, index) => value === array2[index])

(Примечание: здесь «скаляр» означает значения, которые можно сравнивать напрямую, используя ===. Таким образом: числа, строки, объекты по ссылке, функции по ссылке. См. Ссылку MDN для получения дополнительной информации об операторах сравнения).

ОБНОВИТЬ

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

array1.length === array2.length && array1.sort().every(function(value, index) { return value === array2.sort()[index]});

Например:

array1 = [2,3,1,4];
array2 = [1,2,3,4];

Тогда приведенный выше код даст true

user2782196
источник
19
Мне это нравится, хотя читатели должны знать, что это работает только на отсортированных массивах.
Эллен Спертус
13
Он работает с любыми массивами, отсортированными или нет @espertus
Michał Miszczyszyn
36
Да, точно. Эта функция должна сравнивать два массива, не имеет значения, отсортированы они или нет, их последовательные элементы должны быть равны.
Михал Мищишин
22
@espertus Действительно, он не вернет true, если элементы не имеют одинаковый порядок в обоих массивах. Однако цель проверки на равенство состоит не в том, чтобы проверить, содержат ли они одинаковые элементы, а в том, чтобы проверить, имеют ли они один и тот же элемент в одинаковых порядках.
Квентин Рой
7
Если вы хотите проверить, равны ли оба массива одинаковым несортированным элементам (но не использовались несколько раз), вы можете использовать a1.length==a2.length && a1.every((v,i)=>a2.includes(v)): var a1 =[1,2,3], a2 = [3,2,1];( var a1 =[1,3,3], a2 = [1,1,3];не будет работать должным образом)
мемы
208

Мне нравится использовать библиотеку Underscore для проектов тяжелого кодирования массивов / объектов ... в Underscore и Lodash, сравниваете ли вы массивы или объекты, это просто выглядит так:

_.isEqual(array1, array2)   // returns a boolean
_.isEqual(object1, object2) // returns a boolean
Джейсон Бурнер
источник
22
Обратите внимание, что порядок имеет значение _.isEqual([1,2,3], [2,1,3]) => false
Виталий Алекаск
3
или если вам нужна только isEqualфункциональность, вы всегда можете использовать модуль
lodash.isequal
6
Вы можете использовать _.difference (); если заказ не имеет значения для вас
Ронан Кийвере
5
Мы можем отсортировать массив перед проверкой, если порядок не имеет значения_.isEqual([1,2,3].sort(), [2,1,3].sort()) => true
Filype
Самый краткий и прямой ответ ИМХО :-)
Киран Райан
122

Я думаю, что это самый простой способ сделать это с помощью JSON stringify, и это может быть лучшим решением в некоторых ситуациях:

JSON.stringify(a1) === JSON.stringify(a2);

Это преобразует объекты a1и a2в строки , так что они могут быть сопоставлены. Порядок важен в большинстве случаев, поскольку для этого можно отсортировать объект с помощью алгоритма сортировки, показанного в одном из приведенных выше ответов.

Обратите внимание, что вы больше не сравниваете объект, а представляете строковое представление объекта. Это может быть не совсем то, что вы хотите.

radtek
источник
хороший ответ, но почему [] == [] вернуть false? оба простые объекты, то почему?
Пардип Джейн
4
@PardeepJain, это потому, что по умолчанию оператор равенства в ECMAScript для объектов возвращает true, когда они ссылаются на одну и ту же ячейку памяти. Попробуйте var x = y = []; // теперь равенство возвращает true.
Радтек
7
просто чтобы заметить, что функция JSON stringify не является быстрой. Использование с большими массивами определенно приведет к отставанию.
Лукас Лиезис
6
В частности, вопрос заключается в том, существует ли лучший / более быстрый способ, чем использование JSON.stringify.
Дон Хэтч
Более подробно о том, почему это может быть хорошим решением для некоторых ситуаций.
Радтек
61

Непонятно, что вы подразумеваете под «тождественным». Например, идентичны ли массивы aи bниже (обратите внимание на вложенные массивы)?

var a = ["foo", ["bar"]], b = ["foo", ["bar"]];

Вот оптимизированная функция сравнения массивов, которая сравнивает соответствующие элементы каждого массива по очереди, используя строгое равенство, и не выполняет рекурсивное сравнение элементов массива, которые сами являются массивами, что означает, что для приведенного выше примера arraysIdentical(a, b)будет возвращено false. Он работает в общем случае, который JSON и join()решения не будут:

function arraysIdentical(a, b) {
    var i = a.length;
    if (i != b.length) return false;
    while (i--) {
        if (a[i] !== b[i]) return false;
    }
    return true;
};
Тим Даун
источник
@ASDF: из вопроса неясно, что означает «идентичный». Очевидно, что этот ответ просто проверяет. Я добавлю заметку.
Тим Даун
это не работает для массивов идентичных ([1, 2, [3, 2]], [1, 2, [3, 2]]);
Гопинатх Шива
4
@GopinathShiva: Ну, это не удастся, только если вы ожидаете его возвращения true. Ответ объясняет, что это не так. Если вам нужно сравнить вложенные массивы, вы можете легко добавить рекурсивную проверку.
Тим Даун
59

Практический путь

Я думаю, что неправильно говорить, что конкретная реализация является «Правильным путем», если она только «правильная» («правильная») в отличие от «неправильного» решения. Решение Томаша - это явное улучшение по сравнению со сравнением массивов на основе строк, но это не значит, что оно объективно «правильно». Что правильно в любом случае? Это самый быстрый? Это самый гибкий? Это легче всего понять? Это самый быстрый для отладки? Использует ли он наименьшее количество операций? Есть ли у него побочные эффекты? Ни одно решение не может быть лучшим из всех.

Томаш мог бы сказать, что его решение быстрое, но я бы сказал, что оно слишком сложное. Он пытается быть универсальным решением, которое работает для всех массивов, вложенных или нет. Фактически, он даже принимает в качестве входных данных больше, чем просто массивы, и все еще пытается дать «правильный» ответ.


Дженерики предлагают повторное использование

Мой ответ подойдет к проблеме по-другому. Я начну с общей arrayCompareпроцедуры, которая касается только перехода по массивам. Оттуда мы создадим другие наши базовые функции сравнения, такие как arrayEqualи arrayDeepEqualт. Д.

// arrayCompare :: (a -> a -> Bool) -> [a] -> [a] -> Bool
const arrayCompare = f => ([x,...xs]) => ([y,...ys]) =>
  x === undefined && y === undefined
    ? true
    : Boolean (f (x) (y)) && arrayCompare (f) (xs) (ys)

На мой взгляд, лучший вид кода даже не нуждается в комментариях, и это не исключение. Здесь так мало всего происходит, что вы можете понять поведение этой процедуры практически без усилий. Конечно, некоторые синтаксисы ES6 могут показаться вам чуждыми, но это только потому, что ES6 является относительно новым.

Как предполагает тип, arrayCompareпринимает функцию сравнения f, и два входных массива, xsи ys. По большей части все, что мы делаем, это вызываем f (x) (y)каждый элемент во входных массивах. Мы возвращаем досрочно, falseесли пользовательские fвозвраты false- благодаря &&оценке короткого замыкания. Так что да, это означает, что компаратор может остановить итерацию на ранней стадии и предотвратить циклическое прохождение через остальную часть входного массива, когда в этом нет необходимости.


Строгое сравнение

Затем, используя нашу arrayCompareфункцию, мы можем легко создавать другие функции, которые могут нам понадобиться. Начнем с элементарного arrayEqual

// equal :: a -> a -> Bool
const equal = x => y =>
  x === y // notice: triple equal

// arrayEqual :: [a] -> [a] -> Bool
const arrayEqual =
  arrayCompare (equal)

const xs = [1,2,3]
const ys = [1,2,3]
console.log (arrayEqual (xs) (ys))      //=> true
// (1 === 1) && (2 === 2) && (3 === 3)  //=> true

const zs = ['1','2','3']
console.log (arrayEqual (xs) (zs))      //=> false
// (1 === '1')                          //=> false

Просто как тот. arrayEqualможно определить с arrayCompareпомощью функции сравнения, которая сравнивается aс bиспользованием ===(для строгого равенства).

Обратите внимание, что мы также определяем equalкак его собственную функцию. Это подчеркивает роль arrayCompareфункции высшего порядка для использования нашего компаратора первого порядка в контексте другого типа данных (Array).


Слабое сравнение

Мы могли бы так же легко определить, arrayLooseEqualиспользуя ==вместо этого. Теперь при сравнении 1(Number) с '1'(String) результат будет true

// looseEqual :: a -> a -> Bool
const looseEqual = x => y =>
  x == y // notice: double equal

// arrayLooseEqual :: [a] -> [a] -> Bool
const arrayLooseEqual =
  arrayCompare (looseEqual)

const xs = [1,2,3]
const ys = ['1','2','3']
console.log (arrayLooseEqual (xs) (ys))    //=> true
// (1 == '1') && (2 == '2') && (3 == '3')  //=> true

Глубокое сравнение (рекурсивное)

Вы, наверное, заметили, что это только поверхностное сравнение. Конечно, решение Томаша - «Правильный путь ™», потому что оно подразумевает глубокое сравнение, верно?

Что ж, наша arrayCompareпроцедура достаточно универсальна, чтобы использовать ее таким образом, чтобы сделать тест на глубокое равенство быстрым…

// isArray :: a -> Bool
const isArray =
  Array.isArray

// arrayDeepCompare :: (a -> a -> Bool) -> [a] -> [a] -> Bool
const arrayDeepCompare = f =>
  arrayCompare (a => b =>
    isArray (a) && isArray (b)
      ? arrayDeepCompare (f) (a) (b)
      : f (a) (b))

const xs = [1,[2,[3]]]
const ys = [1,[2,['3']]]
console.log (arrayDeepCompare (equal) (xs) (ys)) //=> false
// (1 === 1) && (2 === 2) && (3 === '3')         //=> false

console.log (arrayDeepCompare (looseEqual) (xs) (ys)) //=> true
// (1 == 1) && (2 == 2) && (3 == '3')                 //=> true

Просто как тот. Мы строим глубокий компаратор, используя другую функцию более высокого порядка. На этот раз мы arrayCompareиспользуем специальный компаратор, который проверяет, являются ли массивы aи bесть ли они. Если это так, повторно примените arrayDeepCompareсравнение aи bк указанному пользователем компаратору ( f). Это позволяет нам отделить поведение глубокого сравнения от того, как мы на самом деле сравниваем отдельные элементы. Т.е., как в примере выше показывает, мы можем глубоко сравнить с помощью equal, looseEqualили любой другой компаратор мы делаем.

Поскольку arrayDeepCompareэто карри, мы можем частично применить его так же, как и в предыдущих примерах

// arrayDeepEqual :: [a] -> [a] -> Bool
const arrayDeepEqual =
  arrayDeepCompare (equal)

// arrayDeepLooseEqual :: [a] -> [a] -> Bool
const arrayDeepLooseEqual =
  arrayDeepCompare (looseEqual)

Для меня это уже явное улучшение по сравнению с решением Томаша, потому что я могу явно выбрать поверхностное или глубокое сравнение для своих массивов, если необходимо.


Сравнение объектов (пример)

А что если у вас есть массив объектов или что-то еще? Может быть, вы хотите считать эти массивы "равными", если каждый объект имеет одинаковое idзначение ...

// idEqual :: {id: Number} -> {id: Number} -> Bool
const idEqual = x => y =>
  x.id !== undefined && x.id === y.id

// arrayIdEqual :: [a] -> [a] -> Bool
const arrayIdEqual =
  arrayCompare (idEqual)

const xs = [{id:1}, {id:2}]
const ys = [{id:1}, {id:2}]
console.log (arrayIdEqual (xs) (ys)) //=> true
// (1 === 1) && (2 === 2)            //=> true

const zs = [{id:1}, {id:6}]
console.log (arrayIdEqual (xs) (zs)) //=> false
// (1 === 1) && (2 === 6)            //=> false

Просто как тот. Здесь я использовал ванильные объекты JS, но этот тип компаратора может работать для любого типа объекта; даже ваши пользовательские объекты. Решение Томаша должно быть полностью переработано для поддержки такого теста на равенство

Глубокий массив с объектами? Не проблема. Мы создали универсальные, универсальные функции, поэтому они будут работать в самых разных случаях.

const xs = [{id:1}, [{id:2}]]
const ys = [{id:1}, [{id:2}]]
console.log (arrayCompare (idEqual) (xs) (ys))     //=> false
console.log (arrayDeepCompare (idEqual) (xs) (ys)) //=> true

Произвольное сравнение (пример)

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

// gt :: Number -> Number -> Bool
const gt = x => y =>
  x > y

// arrayGt :: [a] -> [a] -> Bool
const arrayGt = arrayCompare (gt)

const xs = [5,10,20]
const ys = [2,4,8]
console.log (arrayGt (xs) (ys))     //=> true
// (5 > 2) && (10 > 4) && (20 > 8)  //=> true

const zs = [6,12,24]
console.log (arrayGt (xs) (zs))     //=> false
// (5 > 6)                          //=> false

Меньше - больше

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

С легкостью, мы можем точно определить , как мы хотим , два массива для сравнения - мелкий, глубокий, строгий, свободный, некоторые свойства объекта, или некоторые произвольные вычисления, или любая комбинация из них - все с помощью одной процедуры , arrayCompare. Может быть, даже мечтать о RegExpкомпараторе! Я знаю, как дети любят эти регулярные выражения ...

Это самый быстрый? Нет. Но это, вероятно, не должно быть либо. Если бы скорость была единственным показателем, используемым для измерения качества нашего кода, было бы выброшено много действительно хорошего кода - вот почему я называю этот подход Практическим путем . Или , может быть более справедливым, Практический подход. Это описание подходит для этого ответа, потому что я не говорю, что этот ответ только практичен по сравнению с некоторым другим ответом; это объективно верно. Мы достигли высокой степени практичности с очень небольшим количеством кода, который очень легко рассуждать. Ни один другой код не может сказать, что мы не заработали это описание.

Это делает это "правильным" решением для вас? Это для вас , чтобы решить. И никто другой не может сделать это для вас; только вы знаете, каковы ваши потребности. Почти во всех случаях я ценю простой, практичный и универсальный код перед умным и быстрым. То, что вы цените, может отличаться, поэтому выберите то, что вам подходит.


редактировать

Мой старый ответ был больше сфокусирован на разложении arrayEqualна крошечные процедуры. Это интересное упражнение, но не самый лучший (самый практичный) способ решения этой проблемы. Если вам интересно, вы можете увидеть эту историю изменений.

Спасибо
источник
8
«лучший вид кода даже не нуждается в комментариях» ... очень неприятно это говорить, но этот код может использовать больше комментариев и / или другого имени - «сравнение» довольно расплывчато. Если я правильно читаю, ваше "сравнение" по сути является рекурсивным карри "каждый". Я думаю. Или это карри с рекурсивными "некоторыми"? Хм. Это требует больше размышлений, чем необходимо. Возможно, лучшим названием будет «arraysEquivalent», использующее стандартную терминологию «отношение эквивалентности». Или, еще яснее (для меня в любом случае), "рекурсивно-эквивалентный".
Дон Хэтч
1
@DonHatch спасибо за возможность ответить. Вы имеете в виду «сравнить» arrayCompare? Да, функция карри, но она отличается от someи every. arrayCompareберет компаратор и два массива для сравнения. Я выбрал конкретно общее имя, потому что мы можем сравнивать массивы, используя любую произвольную функцию. Функция является карри, поэтому она может быть специализированной для создания новых функций сравнения массивов (например, arrayEqual). Можете ли вы предложить лучшее имя? Какие области, по вашему мнению, требуют дополнительных комментариев или объяснений? Я рад обсудить ^ _ ^
Спасибо,
1
Не уверен, что моя точка зрения ясна - но моя точка зрения заключается в том, что ваша функция на самом деле не предназначена для того, чтобы принимать произвольную функцию, я не думаю - она ​​предназначена для принятия отношения эквивалентности и возвращает отношение эквивалентности. Это важно - это не сделало бы ничего разумного (я не думаю), если бы дали какую-то другую разновидность произвольной двоичной функции, подобной той, которую я упомянул, даже те, которые люди часто называют «сравнивать». Поэтому я думаю, что было бы полезно поставить «эквивалент» в названии вместо «сравнить».
Дон Хэтч
1
@ftor, автор: супер полезный ответ, хорошая работа, +1. Обратная связь: Вы поддерживаете простоту, но ни для кого не существует простого и понятного для многих разработчиков выражения с тремя стрелками на одной строке. Например: f => ([x, ... xs]) => ([y, ... ys]) =>. Я постоянно использую это и все еще должен был мысленно разложить это, а не "просто смотреть на это". Второй пункт прав, используйте каждый. Даже если взвесить ваши соображения, в целом это кажется лучше не только мне, но и с вашей точки зрения, когда вы пытаетесь сделать вывод о вашей философии дизайна.
Whitneyland
1
Я понимаю, что это место для обучения, но я предполагаю, что обычный программист, изучающий функциональный стиль, может преобразовать любую функцию с каррингом в функцию без функции. Мой ответ не дает оснований предполагать, что этот стиль предназначен для использования в вашей собственной программе - пишите его не спеша, пишите его, используя свои собственные правила отступов, пишите так, как вы хотите - я пишу свои ответы в стиле, который, как мне кажется, выражает программа лучшая Я также хотел бы пригласить других людей оспорить то, как мы выражаем наши программы синтаксически
спасибо
54

В духе оригинального вопроса:

Я хотел бы сравнить два массива ... в идеале, эффективно . Ничего особенного , просто правда, если они идентичны, и ложь, если нет.

Я проводил тесты производительности на некоторых из более простых предложений, предложенных здесь, со следующими результатами (от быстрого до медленного):

в то время как (67%) Тимом Дауном

var i = a1.length;
while (i--) {
    if (a1[i] !== a2[i]) return false;
}
return true

каждый (69%) от пользователя2782196

a1.every((v,i)=> v === a2[i]);

уменьшить (74%) по DEI

a1.reduce((a, b) => a && a2.includes(b), true);

присоединиться к & ToString (78%) от Gaizka Альенде & Vivek

a1.join('') === a2.join('');

a1.toString() === a2.toString();

половина строки (90%) Виктора Паломо

a1 == a2.toString();

stringify (100%) от radtek

JSON.stringify(a1) === JSON.stringify(a2);

Обратите внимание, что в приведенных ниже примерах предполагается, что массивы - это отсортированные одномерные массивы. .lengthсравнение было удалено для общего теста (добавьте a1.length === a2.lengthк любому из предложений, и вы получите повышение производительности на ~ 10%). Выберите любые решения, которые лучше всего подходят для вас, зная скорость и ограничения каждого из них.

Несвязанное примечание: интересно видеть людей, получающих всех довольных Джоном Уэйнсом нажатием кнопки «вниз» на совершенно законных ответах на этот вопрос.

unitario
источник
По ссылке открывается пустой тест.
Александр Абакумов
Если вы увеличите размер массива, эти числа не будут применяться (особенно подход сокращения). Попробуйте с Array.from({length: 1000}).map((a,v)=> $ {v}.padStart(10,2));
Нарайон
это работает только для мелкого массива
Рамеш Раджендран
28

Опираясь на ответ Томаша Зато, я согласен, что итерация по массивам - самая быстрая. Кроме того (как уже говорили другие), функцию следует называть равной / равной, а не сравнивать. В свете этого я изменил функцию для обработки сравнения массивов на предмет сходства - т.е. они имеют одинаковые элементы, но не по порядку - для личного использования, и подумал, что я добавлю это здесь для всеобщего обозрения.

Array.prototype.equals = function (array, strict) {
    if (!array)
        return false;

    if (arguments.length == 1)
        strict = true;

    if (this.length != array.length)
        return false;

    for (var i = 0; i < this.length; i++) {
        if (this[i] instanceof Array && array[i] instanceof Array) {
            if (!this[i].equals(array[i], strict))
                return false;
        }
        else if (strict && this[i] != array[i]) {
            return false;
        }
        else if (!strict) {
            return this.sort().equals(array.sort(), true);
        }
    }
    return true;
}

Эта функция принимает дополнительный параметр strict, который по умолчанию принимает значение true. Этот строгий параметр определяет, должны ли массивы быть полностью одинаковыми как по содержанию, так и по порядку их содержания, или просто содержать одно и то же содержимое.

Пример:

var arr1 = [1, 2, 3, 4];
var arr2 = [2, 1, 4, 3];  // Loosely equal to 1
var arr3 = [2, 2, 3, 4];  // Not equal to 1
var arr4 = [1, 2, 3, 4];  // Strictly equal to 1

arr1.equals(arr2);         // false
arr1.equals(arr2, false);  // true
arr1.equals(arr3);         // false
arr1.equals(arr3, false);  // false
arr1.equals(arr4);         // true
arr1.equals(arr4, false);  // true

Я также написал быстрый jsfiddle с помощью функции и этого примера:
http://jsfiddle.net/Roundaround/DLkxX/

Эван Стейнкершнер
источник
12

Несмотря на то, что у этого есть много ответов, я полагаю, что это поможет:

const newArray = [ ...new Set( [...arr1, ...arr2] ) ]

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

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

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


Edit1.

Отвечая на вопрос Дмитрия Гринько: «Почему вы использовали оператор распространения (...) здесь - ... новый сет? Он не работает»

Рассмотрим этот код:

const arr1 = [ 'a', 'b' ]
const arr2 = [ 'a', 'b', 'c' ]
const newArray = [ new Set( [...arr1, ...arr2] ) ]
console.log(newArray)

Ты получишь

[ Set { 'a', 'b', 'c' } ]

Чтобы работать с этим значением, вам нужно использовать некоторые свойства Set (см. Https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set ). С другой стороны, когда вы используете этот код:

const arr1 = [ 'a', 'b' ]
const arr2 = [ 'a', 'b', 'c' ]
const newArray = [ ...new Set( [...arr1, ...arr2] ) ]
console.log(newArray)

Ты получишь

[ 'a', 'b', 'c' ]

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

Джефферсон Евклид
источник
Почему вы использовали оператор распространения (...) здесь - ... новый сет? Не работает
Дмитрий Гринько
Дмитрий Гринько Я думаю, что я ответил на ваш вопрос на моем Edit1. Но я не уверен, что вы имели в виду, говоря «это не работает», так как оба ответа могут вам
помешать
10

В тех же строках, что и в JSON.encode, используется join ().

function checkArrays( arrA, arrB ){

    //check if lengths are different
    if(arrA.length !== arrB.length) return false;


    //slice so we do not effect the original
    //sort makes sure they are in order
    //join makes it a string so we can do a string compare
    var cA = arrA.slice().sort().join(","); 
    var cB = arrB.slice().sort().join(",");

    return cA===cB;

}

var a = [1,2,3,4,5];
var b = [5,4,3,2,1];
var c = [1,2,3,4];
var d = [1,2,3,4,6];
var e = ["1","2","3","4","5"];  //will return true

console.log( checkArrays(a,b) );  //true
console.log( checkArrays(a,c) );  //false
console.log( checkArrays(a,d) );  //false
console.log( checkArrays(a,e) );  //true

Единственная проблема в том, что вы заботитесь о типах, которые тестирует последнее сравнение. Если вы заботитесь о типах, вам придется зацикливаться.

function checkArrays( arrA, arrB ){

    //check if lengths are different
    if(arrA.length !== arrB.length) return false;

    //slice so we do not effect the orginal
    //sort makes sure they are in order
    var cA = arrA.slice().sort(); 
    var cB = arrB.slice().sort();

    for(var i=0;i<cA.length;i++){
         if(cA[i]!==cB[i]) return false;
    }

    return true;

}

var a = [1,2,3,4,5];
var b = [5,4,3,2,1];
var c = [1,2,3,4];
var d = [1,2,3,4,6];
var e = ["1","2","3","4","5"];

console.log( checkArrays(a,b) );  //true
console.log( checkArrays(a,c) );  //false
console.log( checkArrays(a,d) );  //false
console.log( checkArrays(a,e) );  //false

Если порядок должен оставаться тем же, чем просто цикл, сортировка не требуется.

function checkArrays( arrA, arrB ){

    //check if lengths are different
    if(arrA.length !== arrB.length) return false;


    for(var i=0;i<arrA.length;i++){
         if(arrA[i]!==arrB[i]) return false;
    }

    return true;

}

var a = [1,2,3,4,5];
var b = [5,4,3,2,1];
var c = [1,2,3,4];
var d = [1,2,3,4,6];
var e = ["1","2","3","4","5"];

console.log( checkArrays(a,a) );  //true
console.log( checkArrays(a,b) );  //false
console.log( checkArrays(a,c) );  //false
console.log( checkArrays(a,d) );  //false
console.log( checkArrays(a,e) );  //false
epascarello
источник
3
Это работает только для определенных массивов и будет очень медленным с большими массивами.
Томаш Зато - Восстановить Монику
2
Генерация JSON тоже циклична, вы просто (или, кажется, так) не знаете об этом. Помимо зацикливания генерация JSON также требует больше памяти - перед сравнением создает 2 строковых представления указанных массивов. Функция downwote реализована для упорядочения ответов от лучших к худшим. Я думаю, что ваш ответ не очень хороший ответ, поэтому я отказался от него.
Томаш Зато - Восстановить Монику
2
Извините, я просто сказал JSON вместо .join(). Возможно, если бы вы назвали ваше второе решение первичным (поскольку оно лучше, хотя и беззубое по сравнению с многомерными массивами), я бы не стал судить вас таким образом. До сих пор я преуменьшал все ответы, которые преобразовывают массивы в строки. Кроме того, я проголосовал за всех, кто использует правильный путь, на случай, если вам нужно это знать. Это означает ответ @Tim Down и Bireys один.
Томаш Зато - Восстановить Монику
6
Первая версия терпит неудачу: checkArrays([1,2,3] , ["1,2",3]) == trueи очень маловероятно, что именно этого вы и хотите добиться!
делаешь
2
@epascarello: Да, вы можете, но (помимо неэффективности предложенного вами очень длинного разделителя) это означает, что будут крайние случаи (когда массив содержит строку с вашим разделителем в нем), где функция checkArrays () работает неправильно , Это может не быть проблемой, если вы знаете что-то о содержимом массивов (так что вы можете выбрать разделитель, которого вы точно не найдете в элементах массива), но если вы пытаетесь написать общее сравнение массивов функция, то использование join()как это делает его слегка глючным!
Doin
7

Вот версия Typescript:

//https://stackoverflow.com/a/16436975/2589276
export function arraysEqual<T>(a: Array<T>, b: Array<T>): boolean {
    if (a === b) return true
    if (a == null || b == null) return false
    if (a.length != b.length) return false

    for (var i = 0; i < a.length; ++i) {
        if (a[i] !== b[i]) return false
    }
    return true
}

//https://stackoverflow.com/a/16436975/2589276
export function arraysDeepEqual<T>(a: Array<T>, b: Array<T>): boolean {
    return JSON.stringify(a) === JSON.stringify(b)
}

Некоторые тесты для мокко:

it('arraysEqual', function () {
    let a = [1,2]
    let b = [1,2]
    let c = [2,3]
    let d = [2, 3]
    let e = ['car','apple','banana']
    let f = ['car','apple','banana']
    let g = ['car','apple','banan8']

    expect(arraysEqual(a, b)).to.equal(true)
    expect(arraysEqual(c, d)).to.equal(true)
    expect(arraysEqual(a, d)).to.equal(false)
    expect(arraysEqual(e, f)).to.equal(true)
    expect(arraysEqual(f, g)).to.equal(false)
})

it('arraysDeepEqual', function () {
    let a = [1,2]
    let b = [1,2]
    let c = [2,3]
    let d = [2, 3]
    let e = ['car','apple','banana']
    let f = ['car','apple','banana']
    let g = ['car','apple','banan8']
    let h = [[1,2],'apple','banan8']
    let i = [[1,2],'apple','banan8']
    let j = [[1,3],'apple','banan8']

    expect(arraysDeepEqual(a, b)).to.equal(true)
    expect(arraysDeepEqual(c, d)).to.equal(true)
    expect(arraysDeepEqual(a, d)).to.equal(false)
    expect(arraysDeepEqual(e, f)).to.equal(true)
    expect(arraysDeepEqual(f, g)).to.equal(false)
    expect(arraysDeepEqual(h, i)).to.equal(true)
    expect(arraysDeepEqual(h, j)).to.equal(false)
})
Esqarrouth
источник
6

Если вы используете среду тестирования, такую ​​как Mocha, с библиотекой утверждений Chai , вы можете использовать глубокое равенство для сравнения массивов.

expect(a1).to.deep.equal(a2)

Это должно возвращать true, только если массивы имеют равные элементы с соответствующими индексами.

metakermit
источник
6

Если они представляют собой два массива чисел или только строки, это быстрый однострочный

const array1 = [1, 2, 3];
const array2 = [1, 3, 4];
console.log(array1.join(',') === array2.join(',')) //false

const array3 = [1, 2, 3];
const array4 = [1, 2, 3];
console.log(array3.join(',') === array4.join(',')) //true
Гайзка Альенде
источник
const array1 = [1]; const array2 = [1, 1]; console.log (array1.join ('') === array2.join ('')) // возвращает true
Дан М.
это не должно быть: array1.join ('') равно '1', а array2.join ('') равно '11'
Гайска Альенде
извини, опечатка. Первый массив должен быть [11]. Довольно очевидно, почему это происходит и как это исправить.
Дэн М.
Не уверен, что вы имеете в виду, это довольно просто: [1] .join () равно "1", а [1,1] .join () равно "1,1", поэтому они никогда не будут равны
Gaizka Allende
пожалуйста, прочитайте мой комментарий еще более внимательно. Если вы все еще не видите его, пожалуйста, возьмите лут на ideone.com/KFu427
Дэн М.
5

В моем случае сравниваемые массивы содержат только цифры и строки. Эта функция покажет вам, если массивы содержат одинаковые элементы.

function are_arrs_match(arr1, arr2){
    return arr1.sort().toString() === arr2.sort().toString()
}

Давайте проверим это!

arr1 = [1, 2, 3, 'nik']
arr2 = ['nik', 3, 1, 2]
arr3 = [1, 2, 5]

console.log (are_arrs_match(arr1, arr2)) //true
console.log (are_arrs_match(arr1, arr3)) //false
yesnik
источник
Вопрос не просит вас разобраться, поэтому ваше решение не подходит для таких примеров, как are_arrs_equal([1,2], [2,1]). Кроме того, посмотрите другие обсуждения на этой странице, чтобы узнать, почему строковые функции не нужны, хрупки и неправильны.
хорошо относитесь к своим модам
are_arrs_equal([1,2], [2,1])возвращается, trueкак и ожидалось. Возможно, это решение не идеальное, но оно сработало для меня.
да,
В этом-то и проблема, эти два не равны в любом здравом смысле слова «равно» для упорядоченной структуры данных. Это массивы, а не множества, и если вы хотите установить равенство, вы должны назвать это так - и отвечать на другой вопрос. :-)
хорошо относитесь к своим модам
1
Я согласен с комментариями выше, но это решение также работает для меня в моих простых массивах целых чисел, где порядок не важен, поэтому я буду его использовать.
Томазалин
1
Сбой для are_arrs_match([1,2], ["1,2"])(возврат true). И обратите внимание, что the sort()call изменит входные массивы - это может быть нежелательно.
попробуй поймай наконец
5

Это сравнивает 2 несортированных массива:

function areEqual(a, b) {
  if ( a.length != b.length) {
    return false;
  }
  return a.filter(function(i) {
    return !b.includes(i);
  }).length === 0;  
}
Натан Булиан Трухильо
источник
Несмотря на высокую стоимость (с точки зрения вычислительных ресурсов), это надежное решение, которое должно подойти для различных типов и не полагаться на сортировку!
user3.1415927
5

Для массива чисел попробуйте:

a1==''+a2

Примечание: этот метод не будет работать, когда массив также содержит строки, например a2 = [1, "2,3"].

Камил Келчевски
источник
хитрый трюк ..
Джавадба
4

Мы могли бы сделать это функциональным способом, используя every( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/every )

function compareArrays(array1, array2) {
    if (array1.length === array2.length)
        return array1.every((a, index) => a === array2[index])
    else
        return false
}

// test
var a1 = [1,2,3];
var a2 = [1,2,3];

var a3 = ['a', 'r', 'r', 'a', 'y', '1']
var a4 = ['a', 'r', 'r', 'a', 'y', '2']

console.log(compareArrays(a1,a2)) // true
console.log(compareArrays(a1,a3)) // false
console.log(compareArrays(a3,a4)) // false
peonicles
источник
4

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

Посмотрите на мой код с вашим примером, который сравнивает два массива, элементы которых являются числами, вы можете изменить или расширить его для других типов элементов (используя .join () вместо .toString ()).

var a1 = [1,2,3];
var a2 = [1,2,3];
const arraysAreEqual = a1.sort().toString()==a2.sort().toString();
// true if both arrays have same elements else false
console.log(arraysAreEqual);

Дурга Патра
источник
3

Вот мое решение:

/**
 * Tests two data structures for equality
 * @param {object} x
 * @param {object} y
 * @returns {boolean}
 */
var equal = function(x, y) {
    if (typeof x !== typeof y) return false;
    if (x instanceof Array && y instanceof Array && x.length !== y.length) return false;
    if (typeof x === 'object') {
        for (var p in x) if (x.hasOwnProperty(p)) {
            if (typeof x[p] === 'function' && typeof y[p] === 'function') continue;
            if (x[p] instanceof Array && y[p] instanceof Array && x[p].length !== y[p].length) return false;
            if (typeof x[p] !== typeof y[p]) return false;
            if (typeof x[p] === 'object' && typeof y[p] === 'object') { if (!equal(x[p], y[p])) return false; } else
            if (x[p] !== y[p]) return false;
        }
    } else return x === y;
    return true;
};

Работает с любой вложенной структурой данных и, очевидно, игнорирует методы объектов. Даже не думайте о расширении Object.prototype с помощью этого метода, когда я однажды попробовал это сделать, jQuery сломался;)

Для большинства массивов это все же быстрее, чем у большинства решений для сериализации. Это, пожалуй, самый быстрый метод сравнения массивов записей объектов.

Гарри
источник
не хорошо! они дают правду: equal({}, {a:1})и equal({}, null)это ошибки:equal({a:2}, null)
kristianlm
3
JSON.stringify(collectionNames).includes(JSON.stringify(sourceNames)) ?  array.push(collection[i]) : null

Вот как я это сделал.

Лид
источник
Хорошее решение - но мне интересно в некоторых ситуациях, если оно не всегда будет работать так, как задумано, например, с некоторыми примитивами или глубоко вложенными массивами? Я надеюсь, что это работает при любых обстоятельствах
Бен Рондо
3

Сравнивая 2 массива:

var arr1 = [1,2,3];
var arr2 = [1,2,3];

function compare(arr1,arr2)
{
  if((arr1 == arr2) && (arr1.length == arr2.length))
    return true;
  else
    return false;
}

вызывающая функция

var isBool = compare(arr1.sort().join(),arr2.sort().join());
Амай Кулкарни
источник
Этот ответ не будет работать, так как === не работает так, как ожидается для массивов.
Майкл Ян
Ответ работает, хотя === здесь не имеет никакого значения (поскольку sort () работает только с массивом). Даже == тоже будет работать.
Amay Kulkarni
Попробуйте сами; выдает false, если вы запускаете этот код. Это из-за сравнения эталонных значений массивов как ==, так и === вместо их фактических значений. == и === предназначены только для сравнения примитивных типов.
Майкл Ян
Он возвращает true, мы его использовали, но я удалил '===' сейчас, так как он не является обязательным
Kulkarni
Ах, я не заметил, что вы конвертировали в строку и вызывали функцию после сортировки и объединения; мои извинения.
Майкл Ян
3

Я считаю , что в простом JSи ECMAScript 2015, который сладок и прост для понимания.

var is_arrays_compare_similar = function (array1, array2) {

    let flag = true;

    if (array1.length == array2.length) {

        // check first array1 object is available in array2 index
        array1.every( array_obj => {
            if (flag) {
                if (!array2.includes(array_obj)) {
                    flag = false;
                }
            }
        });

        // then vice versa check array2 object is available in array1 index
        array2.every( array_obj => {
            if (flag) {
                if (!array1.includes(array_obj)) {
                    flag = false;
                }
            }
        });

        return flag;
    } else {
        return false;
    }

}

надеюсь, это кому-нибудь поможет.

ArifMustafa
источник
1
Зачем нужна обратная проверка? Мы знаем, что массивы имеют одинаковый размер, поэтому, если каждый элемент в array1 также находится в array2; зачем нам тогда проверять, что каждый элемент в array2 также находится в array1?
JeffryHouser
2

Расширение идеи Томаша Зато. Array.prototype.compare Томаса должен быть на самом деле Array.prototype.compareIdentical.

Он проходит по:

[1, 2, [3, 4]].compareIdentical ([1, 2, [3, 2]]) === false;
[1, "2,3"].compareIdentical ([1, 2, 3]) === false;
[1, 2, [3, 4]].compareIdentical ([1, 2, [3, 4]]) === true;
[1, 2, 1, 2].compareIdentical ([1, 2, 1, 2]) === true;

Но терпит неудачу на:

[[1, 2, [3, 2]],1, 2, [3, 2]].compareIdentical([1, 2, [3, 2],[1, 2, [3, 2]]])

Вот лучшая (на мой взгляд) версия:

Array.prototype.compare = function (array) {
    // if the other array is a falsy value, return
    if (!array)
        return false;

    // compare lengths - can save a lot of time
    if (this.length != array.length)
        return false;

    this.sort();
    array.sort();
    for (var i = 0; i < this.length; i++) {
        // Check if we have nested arrays
        if (this[i] instanceof Array && array[i] instanceof Array) {
            // recurse into the nested arrays
            if (!this[i].compare(array[i]))
                return false;
        }
        else if (this[i] != array[i]) {
            // Warning - two different object instances will never be equal: {x:20} != {x:20}
            return false;
        }
    }
    return true;
}

http://jsfiddle.net/igos/bcfCY/

Игорь Сергеевич
источник
2
-1. Если в примере, который вы привели, он «проваливается», то это только в случае произвольного определения «провалов». Почему вы ожидаете, что эти два разных массива будут считаться равными? Вы даже не объяснили, какую концепцию «равенства» вы пытаетесь реализовать здесь, или почему она разумна или полезна, но похоже, что вы хотите, чтобы многомерные массивы сравнивались так, как если бы они были свернуты в одномерные из них. Если это так, вы даже не достигли этого: [1,2] .compare ([[1,2]]) выдает false с вашей версией, как и с Томашем.
Марк Амери
Исходя из того, что я могу сделать вывод, он говорит, что [1, 2, 3, 4] и [1, 3, 2, 4] следует сравнивать как равные (порядок не имеет значения).
Гаутам Бадхринатан
2
var a1 = [1,2,3,6];
var a2 = [1,2,3,5];

function check(a, b) {
  return (a.length != b.length) ? false : 
  a.every(function(row, index) {
    return a[index] == b[index];
  });
}  

check(a1, a2);

////// ИЛИ ///////

var a1 = [1,2,3,6];
var a2 = [1,2,3,6];

function check(a, b) {
  return (a.length != b.length) ? false : 
  !(a.some(function(row, index) {
    return a[index] != b[index];
  }));
}  

check(a1, a2)
Взант
источник
Вы можете вам какую - то функцию , а также, не будет итерация полностью , если мы получим необходимое условие удовлетворено, как выше
Взант
2

Другой подход с очень небольшим количеством кода (с использованием Array Reduce и Array включает в себя ):

arr1.length == arr2.length && arr1.reduce((a, b) => a && arr2.includes(b), true)

Если вы хотите сравнить также равенство порядка:

arr1.length == arr2.length && arr1.reduce((a, b, i) => a && arr2[i], true)
  • В lengthконтрольном гарантирует , что множество элементов в одном массиве не является лишь подмножеством другого.

  • Редуктор используется для обхода одного массива и поиска каждого элемента в другом массиве. Если один элемент не найден, возвращается функция уменьшения false.

    1. В первом примере проверяется, что элемент включен
    2. Второй пример чека на заказ тоже
Dels
источник
1
Не могли бы вы немного объяснить свой код, чтобы сделать этот ответ более понятным?
Тед
1. сравните длины массивов, чтобы убедиться, что один массив не является подмножеством другого
DEls
2. Используйте редуктор для обхода одного массива и поиска каждого элемента в другом массиве. Если один элемент не найден, функция уменьшения возвращает «ложь»
DEls
@DEls: отредактировал ваше объяснение в ответе (слегка перефразировано и расширено). Теперь вы можете удалить свои комментарии и пометить первый комментарий, а этот - как устаревший.
попробуй поймай, наконец,
2

Простой подход:

function equals(a, b) {
    if ((a && !b) || (!a && b) || (!a && !b) || (a.length !== b.length)) {
        return false;
    }

    var isDifferent = a.some(function (element, index) { 
        return element !== b[index];
    });

    return !isDifferent;
}
Педро Родригес
источник
2

Уже несколько хороших ответов. Но я хотел бы поделиться другой идеей, которая доказала свою надежность при сравнении массивов. Мы можем сравнить два массива, используя JSON.stringify () . Он создаст строку из массива и, таким образом, сравнит две полученные строки из двух массивов на равенство.

JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:1},2]) //true

JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:2},2]) //false

JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:2},[3,4],2]) //false

JSON.stringify([1,{a:1},[3,4],2]) == JSON.stringify([1,{a:2},[3,4],2]) //false

JSON.stringify([1,{a:2},[3,4],2]) == JSON.stringify([1,{a:2},[3,4],2]) //true

JSON.stringify([1,{a:2},[3,4],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //false

JSON.stringify([1,{a:2},[3,4,[4]],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //false

JSON.stringify([1,{a:2},[3,4,[5]],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //true
AL-З
источник
2

Рекурсивно & работает над массивами NESTED :

function ArrEQ(a1,a2){
   return( 
        //:Are both elements arrays?
        Array.isArray(a1)&&Array.isArray(a2) 
        ?
        //:Yes: Test each entry for equality:
        a1.every((v,i)=>(ArrEQ(v,a2[i])))
        :
        //:No: Simple Comparison:
        (a1===a2)
   );;
};;

console.log( "Works With Nested Arrays:" );
console.log( ArrEQ( 
    [1,2,3,[4,5,[6,"SAME/IDENTICAL"]]],
    [1,2,3,[4,5,[6,"SAME/IDENTICAL"]]]
));;     
console.log( ArrEQ( 
    [1,2,3,[4,5,[6,"DIFFERENT:APPLES" ]]],
    [1,2,3,[4,5,[6,"DIFFERENT:ORANGES"]]]
));;  
JMI MADISON
источник
2

Работает с НЕСКОЛЬКИМИ аргументами с массивами NESTED :

//:Return true if all of the arrays equal.
//:Works with nested arrays.
function AllArrEQ(...arrays){
    for(var i = 0; i < (arrays.length-1); i++ ){
        var a1 = arrays[i+0];
        var a2 = arrays[i+1];
        var res =( 
            //:Are both elements arrays?
            Array.isArray(a1)&&Array.isArray(a2) 
            ?
            //:Yes: Compare Each Sub-Array:
            //:v==a1[i]
            a1.every((v,i)=>(AllArrEQ(v,a2[i])))
            :
            //:No: Simple Comparison:
            (a1===a2)
        );;
        if(!res){return false;}
    };;
    return( true );
};;

console.log( AllArrEQ( 
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
));; 
JMI MADISON
источник
2
In a simple way uning stringify but at same time thinking in complex arrays:

**Simple arrays**:  
var a = [1,2,3,4];  
var b = [4,2,1,4];  
JSON.stringify(a.sort()) === JSON.stringify(b.sort()) // true  

**Complex arrays**:  
var a = [{id:5,name:'as'},{id:2,name:'bes'}];  
var b = [{id:2,name:'bes'},{id:5,name:'as'}];  
JSON.stringify(a.sort(function(a,b) {return a.id - b.id})) === JSON.stringify(b.sort(function(a,b) {return a.id - b.id})) // true  

**Or we can create a sort function**  

function sortX(a,b) {  
return a.id -b.id; //change for the necessary rules  
}  
JSON.stringify(a.sort(sortX)) === JSON.stringify(b.sort(sortX)) // true  
Педро Бустаманте
источник