Як порівняти масиви в JavaScript?


988

Я хотів би порівняти два масиви ... в ідеалі, ефективно. Нічого фантазійного, лише 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

55
Що робить два масиви рівними для вас? Однакові елементи? Однаковий порядок елементів? Кодування як JSON працює лише до тих пір, поки елемент масиву може бути серіалізований до JSON. Якщо масив може містити об'єкти, наскільки глибоко ви б пройшли? Коли два об'єкти "рівні"?
Фелікс Клінг

48
@FelixKling, визначення "рівності", безумовно, є тонкою темою, але для людей, які приходять до JavaScript з мов вищого рівня, немає приводу для глупоти, як ([] == []) == false.
Алекс Д

4
@AlexD це схоже на те, що масиви використовують довідкову рівність, яку ви очікували. Було б дуже жахливо, якби ти не зміг цього зробити
JonnyRaa

3
@AlexD Я дещо не можу придумати мову, де цього не відбувається. У C ++ ви б порівнювали два покажчики - хибні. У 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;

Ви можете сказати " Але набагато швидше порівнювати рядки - ніяких циклів ... " ну, тоді вам слід зазначити, що НЕМАЄ циклів. Перший рекурсивний цикл, який перетворює масив у рядок, і другий, який порівнює два рядки. Тож цей метод швидший, ніж використання рядкового .

Я вважаю, що більша кількість даних завжди повинна зберігатися в масивах, а не в об'єктах. Однак якщо ви використовуєте об'єкти, їх також можна частково порівняти.
Ось як:

Порівняння об'єктів:

Я вже заявив, що два екземпляри об'єкта ніколи не будуть рівними, навіть якщо вони містять однакові дані на даний момент:

({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
Nt тільки це правильний спосіб зробити це, це також значно більш ефективно. Ось швидкий сценарій 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


19
Мені це подобається, хоча читачі повинні знати, що це працює лише на відсортованих масивах.
Еллен Спертус

13
Він працює на будь-яких масивах, відсортованих чи не @espertus
Michał Miszczyszyn

36
Так, саме. Ця функція повинна порівнювати два масиви, не важливо, сортуються вони чи ні, їх послідовні елементи повинні бути рівними.
Michał Miszczyszyn

22
@espertus Дійсно, він не повернеться істинним, якщо елементи не мають точно однакового порядку в обох масивах. Однак мета перевірки рівності - не перевірити, чи вони містять однакові елементи, а перевірити, чи є у них однаковий елемент у тих же порядках.
Квентін Рой

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
Філіпе

найкоротша та найпростіша відповідь ІМХО :-)
Кіеран Райан

121

Я думаю, це найпростіший спосіб зробити це за допомогою JSON stringify, і він може бути найкращим рішенням у деяких ситуаціях:

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

Це перетворює об'єкти a1іa2 в рядки , так що вони можуть бути співставлені. Порядок є важливим у більшості випадків, оскільки він може сортувати об'єкт за допомогою алгоритму сортування, показаного в одній з вищевказаних відповідей.

Будь ласка, зауважте, що ви більше не порівнюєте об'єкт, а рядкове представлення об'єкта. Це може бути не саме те, що ви хочете.


хороша відповідь, але чому [] == [] повернути помилкове? обидва є простими об'єктами, то чому?
Pardeep Jain

4
@PardeepJain, це тому, що за замовчуванням оператор рівності в ECMAScript для об'єктів повертає істину, коли вони посилаються на одне місце пам’яті. Спробуйте var x = y = []; // тепер рівність повертає істину.
radtek

7
просто зауважимо, що функція Strify JSON не є швидкою. Використовувані з більшими масивами, безумовно, введуть відставання
Лукас Ліїс

6
Питання конкретно запитує, чи є кращий / швидший спосіб, ніж використання JSON.stringify.
Дон Хетч

Більш детально розбирається, чому це може бути хорошим рішенням для деяких ситуацій.
радтек

61

Незрозуміло, що ви маєте на увазі під «тотожним». Наприклад, чи є масиви aі bнижче однакові (зверніть увагу на вкладені масиви)?

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

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

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: З питання, що означає "ідентичний", незрозуміло. Очевидно, ця відповідь просто неглибоко перевіряє. Я додам записку.
Тім Даун

це не вдається для масивівIdentical ([1, 2, [3, 2]], [1, 2, [3, 2]]);
Gopinath Shiva

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як функції вищого порядку для використання нашого першого компаратора порівняння в контексті іншого типу даних (масив).


Легке порівняння

Ми могли так само легко визначитись, arrayLooseEqualвикористовуючи ==натомість. Тепер, порівнюючи 1(Число) з '1'(Рядок), результат буде 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компаратор! Я знаю, як діти люблять ці виразки ...

Це найшвидше? Ні. Але це, мабуть, не потрібно. Якщо швидкість - єдиний показник, який використовується для вимірювання якості нашого коду, багато справді чудового коду буде відкинуто - саме тому я називаю такий підхід Практичним шляхом . А може бути більш справедливим, A Практичний підхід. Цей опис підходить для цієї відповіді, оскільки я не кажу, що ця відповідь є практичною лише порівняно з якоюсь іншою відповіддю; це об'єктивно вірно. Ми досягли високого ступеня практичності з дуже маленьким кодом, про що дуже легко міркувати. Жоден інший код не може сказати, що ми не заробили цей опис.

Це робить це "правильним" рішенням для вас? Це вам вирішити. І ніхто більше не може цього зробити для вас; тільки ти знаєш, які твої потреби. Майже у всіх випадках я ціную прямий, практичний та універсальний код за розумний та швидкий вид. Те, що ви цінуєте, може відрізнятися, тому виберіть те, що вам підходить.


Редагувати

Моя стара відповідь була більш зосереджена на розкладанні arrayEqualна крихітні процедури. Це цікава вправа, але насправді не найкращий (найпрактичніший) спосіб підійти до цієї проблеми. Якщо вас цікавить, ви можете переглянути цю історію редагувань.


8
"найкращий вид коду навіть не потребує коментарів" ... ненавиджу це говорити, але цей код може використовувати більше коментарів та / або іншу назву - "порівняти" досить розпливчасто. Якщо я читаю правильно, ваше "порівняння" - це по суті криво-рекурсивне "кожен". Я думаю. Або це криво рекурсивне "якесь"? Хм. Для цього потрібно більше мислення, ніж потрібно. Можливо, кращою назвою було б "масив еквівалент", використовуючи стандартну термінологію "відношення еквівалентності". Або, ще зрозуміліше (для мене все одно), "рекурсивно еквівалентний".
Дон Хетч

1
@DonHatch дякую за можливість відповісти. Під "порівнянням" ви маєте на увазі arrayCompare? Так, функція є кривою, але вона відрізняється від someі every. arrayCompareдля порівняння бере компаратор і два масиви. Я вибрав конкретно загальну назву, оскільки ми можемо порівнювати масиви, використовуючи будь-яку довільну функцію. Функція є кривою, тому її можна спеціалізувати на створенні нових функцій порівняння масиву (наприклад, arrayEqual). Чи можете ви запропонувати краще ім’я? Які сфери, на вашу думку, потребують додаткових коментарів чи пояснень? Я радий обговорити ^ _ ^
Дякую

1
Не впевнений, чи ясна моя думка ще зрозуміла - але моя думка полягає в тому, що ваша функція насправді не призначена приймати довільну функцію, я не думаю - вона призначена приймати відношення еквівалентності , і вона повертає відношення еквівалентності. Це важливо - це не зробило б нічого розумного (я не думаю), якби давати якусь іншу довільну бінарну функцію, як ті, про які я згадував, навіть ті, які люди часто називають «порівняти». Тому я думаю, що було б корисно поставити «еквівалент» у назві замість «порівняти».
Дон Хетч

1
@ftor, автор: супер корисна відповідь, хороша робота, +1. Зворотній зв'язок: Ви виступаєте за простоту, але жоден спосіб не є виразом із трьома стрілками на одному рядку простим або зрозумілим для багатьох розробників. Наприклад: f => ([x, ... xs]) => ([y, ... ys]) =>. Я постійно користуюся цим і все-таки мусив подумки розкласти його, а не «просто дивитись на це». Друга точка ftor правильно, використовуйте кожен. Навіть зважуючи ваші причини, на балансі це здається кращим не тільки мені, але й з точки зору вашого погляду, коли ви намагаєтесь зробити висновок про свою філософію дизайну.
Уїтніленд

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

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

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

половина до Стринг (90%) Віктор Паломо

a1 == a2.toString();

Strify (100%) від radtek

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

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

Непов’язана примітка: цікаво бачити, як люди отримують задоволення від тривоги Джона Уейнса, який натискає кнопку "вниз", і цілком законні відповіді на це питання.


Посилання відкриває порожній тест.
Олександр Абакумов

Якщо ви збігаєте розмір масиву, ці числа не застосовуються (особливо зменшення підходу). Спробуйте з Array.from({length: 1000}).map((a,v)=> $ {v}.padStart(10,2));
Narayon

він працює лише для неглибокого масиву
Рамеш Раджендран,

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;
}

Ця функція приймає додатковий параметр строго, що за замовчуванням відповідає істині. Цей суворий параметр визначає, чи повинні масиви бути повністю рівними як за вмістом, так і за порядком цього вмісту, або просто містити однаковий вміст.

Приклад:

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 для усунення дублікатів. Після того, як ви зможете порівняти їх розміри, якщо всі три масиви мають однаковий розмір, ви добре пройти.

Ця відповідь також ігнорує порядок елементів , як я вже сказав, зі мною трапилася точна ситуація, тож, можливо, хтось у тій же ситуації може опинитися тут (як і я).


Правка1.

Відповідаючи на запитання Дмитра Грінко: "Чому ви тут використовували оператор розповсюдження (...) - ... новий комплект? Це не працює"

Розглянемо цей код:

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

Це різниця, перший дав би мені набір, він також працював би, оскільки я міг отримати розмір цього набору, але другий дає мені потрібний масив, що пряміше до роздільної здатності.


Чому ви тут використовували оператор розповсюдження (...) - ... новий набір? Це не працює.
Дмитро Гринько

Дмитро Гринько. Я вважаю, що я відповів на ваше запитання щодо моєї редакції1. Але я не впевнений, що ви мали на увазі, сказавши "це не працює", оскільки обидві відповіді можуть перешкодити вам
Джеферсон Евклід

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

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()подібне, це робить непомітно баггі!
Зробіть

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

6

Якщо ви використовуєте тестовий фреймворк на зразок Mocha з бібліотекою тверджень Chai , ви можете використовувати глибоку рівність для порівняння масивів.

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

Це має повернути істину, лише якщо масиви мають рівні елементи за відповідними індексами.


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 масив1 = [1]; const масив2 = [1, 1]; console.log (array1.join ('') === array2.join ('')) // повертає true
Dan M.

це не повинно: array1.join ('') - '1', а array2.join ('') - '11'
Gaizka Allende

вибачте, друкарня. Перший масив повинен бути [11]. Досить очевидно, чому це відбувається і як виправити.
Дан М.

Не впевнений, що ви маєте на увазі, це досить просто: [1] .join () - це "1", а [1,1] .join () - "1,1", тому вони ніколи не будуть рівними
Gaizka Allende

будь ласка, прочитайте ще раз уважніше мій коментар. Якщо ви все ще не бачите цього, будь ласка, зробіть бабло на ideone.com/KFu427
Dan M.

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

Питання не вимагає сортування, тому ваше рішення неправильне для подібних прикладів are_arrs_equal([1,2], [2,1]). Також дивіться інші дискусії на цій сторінці, чому стримування є непотрібним, крихким та неправильним.
добре

are_arrs_equal([1,2], [2,1])повертається trueяк очікувалося. Можливо, це рішення не є ідеальним, але воно працювало на мене.
yesnik

В цьому і полягає проблема: ці два не є рівними в жодному розумному сенсі слова "рівний" для впорядкованої структури даних. Вони є масивами, а не множинами, і якщо ви хочете встановити рівність, вам слід це назвати - і відповідати на інше питання. :-)
добре

1
Я погоджуюся з коментарями вище, але це рішення також працює для мене в моїх простих масивах цілих чисел, де порядок не важливий, тому я буду його використовувати.
tomazahlin

1
Не вдалося are_arrs_match([1,2], ["1,2"])(повертається true). І зауважте, що the sort()виклик модифікує вхідні масиви - це може бути не бажаним.
try-catch-нарешті

5

Тут порівнюються 2 несортованих масиви:

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

Хоча це дорого (з точки зору обчислювальних ресурсів), це надійне рішення, яке повинно бути корисним для різних типів, а не покладатися на сортування!
користувач3.1415927

5

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

a1==''+a2

Примітка: цей метод не працюватиме, коли масив також містить рядки, наприклад a2 = [1, "2,3"].


розумна хитрість ..
javadba

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

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

Спробуйте самі; він друкує помилковий, якщо ви запустите цей код. Це пояснюється порівнянням опорних значень масивів як ==, так і === замість їх фактичних значень. == та === призначені лише для порівняння примітивних типів.
Майкл Ян

Це повертається правдою, ми використовували його, але я видалив '===' зараз, оскільки це не є обов'язковим
Амай Кулкарні

Ах, я не помітив, що ви переходили до рядка та викликали функцію після сортування та з'єднання; мої вибачення.
Майкл Ян

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;
    }

}

сподіваюся, що це комусь допоможе.


1
Для чого потрібна навпаки перевірка? Ми знаємо, що масиви однакового розміру, тому якщо кожен елемент масиву1 також знаходиться в масиві2; чому ми тоді повинні перевірити, що кожен елемент у масиві2 також є у масиві1?
JeffryHouser

2

Розширення ідеї Томаша Зато. Tomas's 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] .порівняти ([[1,2]]) дає помилкову версію вашої версії, як і версію Томаша.
Марк Амері

На підставі того, що я міг би зробити, він говорить, що [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)

Ви можете також виконати якусь функцію, яка не повториться повністю, якщо ми задовольнимо необхідну умову, як вище
Vasanth

2

Ще один підхід із дуже малою кількістю коду (використовуючи зменшення масиву та включає масив ):

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. Другий приклад перевірити також на замовлення

1
Ви можете трохи пояснити свій код, щоб зробити цю відповідь зрозумілішою?
тед

1. порівняйте довжини масиву, щоб переконатися, що один масив не є підмножиною іншого
DEls

2. за допомогою редуктора пройти по одному масиву та шукати кожен елемент в іншому масиві. Якщо жодного елемента не знайдено, функція зменшення повертається "false"
DEls

@DEls: відредагував ваше пояснення у відповідь (трохи перероблений та розширений). Тепер ви можете видалити свої коментарі та позначити перший коментар, а цей - застарілим.
try-catch-нарешті

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

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"]]]
));;  

2

Працює з ДЕКІЛЬКОМА аргументами з суміщати масивами:

//: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"   ]]],
));; 

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  
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.