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

Я бы хотел сравнить два массива... идеально, эффективно. Ничего необычного, просто 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 кодирует каждый массив, но существует ли более быстрый или "лучший" способ простого сравнения массивов без необходимости повторения каждого значения?

Ответ 1

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

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

// Warn if overriding existing method
if(Array.prototype.equals)
    console.warn("Overriding existing Array.prototype.equals. Possible causes: New API defines the method, there a framework conflict or you've got double inclusions in your code.");
// attach the .equals method to Array 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 циклы. Первый рекурсивный цикл, который преобразует Array в строку и второй, который сравнивает две строки. Таким образом, этот метод быстрее, чем использование строки.

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

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

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

({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 say YES
    return true;
}  

Однако помните, что это должно служить для сравнения JSON как данных, а не экземпляров классов и других вещей. Если вы хотите сравнить mor-сложные объекты, посмотрите на этот ответ и на эту функцию.
Чтобы сделать эту работу с 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

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

Ответ 2

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

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

Ответ 3

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

_.isEqual(array1, array2)   // returns a boolean
_.isEqual(object1, object2) // returns a boolean

Ответ 4

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

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

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

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

Ответ 5

Неясно, что вы подразумеваете под "идентичными". Например, массивы 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;
};

Ответ 6

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

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

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


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

Мой ответ подойдет к проблеме по-разному. Я начну с общей процедуры arrayCompare, которая касается только 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). Это позволяет нам сохранять глубокое сравнительное поведение отдельно от того, как мы фактически сравниваем отдельные элементы. Т.е., как показано в приведенном выше примере, мы можем looseEqual глубокое сравнение с использованием equal, looseEqual или любого другого компаратора, который мы делаем.

Поскольку arrayDeepCompare находится в 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

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

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

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, и каждый из изготовленных нами компараторов имеет очень простую реализацию.

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

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

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


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

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

Ответ 7

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

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

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

пока (67%) by Tim Down

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 Allende и vivek

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

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

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

a1 == a2.toString();

stringify (100%) от radtek

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

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

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

Ответ 8

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

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/

Ответ 9

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

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' ]

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

Ответ 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

Ответ 11

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

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

Ответ 12

Вот версия машинописного текста:

//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)
})

Ответ 13

Если вы используете платформу тестирования, например Mocha, Chai, вы можете использовать deep равенство для сравнения массивов.

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

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

Ответ 14

[Обновление 23-05-2019]

Не используйте метод, описанный ниже. Есть очень хорошие ответы, приведенные выше, используйте один из них.


для одноразмерного массива вы можете просто использовать:

arr1.sort().toString() == arr2.sort().toString()

это также позаботится о массиве с несовпадающим индексом.

Ответ 15

Мы могли бы сделать это функциональным способом, используя 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

Ответ 16

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

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

Ответ 17

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

/**
 * 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 сломался;)

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

Ответ 18

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

function areEqual(a, b) {
  if ( a.length != b.length) {
    return false;
  }
  return a.filter(function(i) {
    return !b.includes(i);
  }).length === 0;  
}

Ответ 19

Расширение идеи Томаша Зато. Tomas Array.prototype.compare должен быть infact, называемый 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/

Ответ 20

Пока == сравнивает указатели на массив, часто забывают, что < и > работают довольно хорошо. Итак, одно простое решение:

  function eq(a,b){return !(a<b || b<a);}

Кажется, что он работает неплохо, но, похоже, немного теряет контроль над типом:

eq([1,2],[])
false
eq([1,2],[1,2,0])
false
eq([1,2,0],[1,2,0])
true
eq([1,2,0],[1,2,null])
false
eq([1,2,0],[1,2,"0"])
true
eq([1,2,0],[1,2,[0]])
true
eq([1,2,[0],[3]],[1,2,[0,3]])
true
eq([1,2,[0],[3]],[1,2,[0,4]])
false
eq([1,2,[0],[3]],[1,2,"0,3"])
true

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

Ответ 21

Другой подход с очень небольшим количеством кода (с помощью 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.

    • В первом примере тестируется, что элемент включен
    • Второй пример также проверяет порядок.

Ответ 22

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)

Ответ 23

JSON.stringify(collectionNames).includes(JSON.stringify(sourceNames)) ?  array.push(collection[i]) : null

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

Ответ 24

Сравнение 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());

Ответ 25

Рекурсивный и работает над массивами 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"]]]
));;  

Ответ 26

Работает с MULTIPLE аргументами с массивами 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"   ]]],
));; 

Ответ 27

Я верю в простой 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;
    }

}

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

Ответ 28

этот script сравнивает объекты, массивы и многомерный массив

function compare(a,b){
     var primitive=['string','number','boolean'];
     if(primitive.indexOf(typeof a)!==-1 && primitive.indexOf(typeof a)===primitive.indexOf(typeof b))return a===b;
     if(typeof a!==typeof b || a.length!==b.length)return false;
     for(i in a){
          if(!compare(a[i],b[i]))return false;
     }
     return true;
}

первая строка проверяет, является ли это примитивным типом. если это так, он сравнивает два параметра.

если они являются объектами. он выполняет итерацию по объекту и проверяет каждый элемент рекурсивно.

Использование:

var a=[1,2,[1,2]];
var b=[1,2,[1,2]];
var isEqual=compare(a,b);  //true

Ответ 29

Эта функция сравнивает два массива произвольной формы и dimesionality:

function equals(a1, a2) {

    if (!Array.isArray(a1) || !Array.isArray(a2)) {
        throw new Error("Arguments to function equals(a1, a2) must be arrays.");
    }

    if (a1.length !== a2.length) {
        return false;
    }

    for (var i=0; i<a1.length; i++) {
        if (Array.isArray(a1[i]) && Array.isArray(a2[i])) {
            if (equals(a1[i], a2[i])) {
                continue;
            } else {
                return false;
            }
        } else {
            if (a1[i] !== a2[i]) {
                return false;
            }
        }
    }

    return true;
}

Ответ 30

Выберите каждый из [a] и пропустите все из [b]: Результат: 1, 5

var a = [1,4,5,9];
var b = [1,6,7,5];

for (i = 0; i < a.length; i++) {
    for (z = 0; z < a.length; z++) {
        if (a[i] === b[z]) {
            console.log(b[z]); // if match > console.log it 
        }
    }
}