Як дізнатися, чи мають два масиви однакові значення


104

У мене є ці два масиви: один заповнюється інформацією із запиту ajax, а інший зберігає кнопки, на які користувач натискає. Я використовую цей код (я заповнив зразки номерів):

var array1 = [2, 4];
var array2 = [4, 2]; //It cames from the user button clicks, so it might be disordered.
array1.sort(); //Sorts both Ajax and user info.
array2.sort();
if (array1==array2) {
    doSomething();
}else{
    doAnotherThing();
}

Але це завжди дає false, навіть якщо два масиви однакові, але з різною назвою. (Я перевірив це на консолі JS Chrome). Отже, чи я можу знати, чи містять ці два масиви однакові? Чому це дає false? Як я можу знати, які значення в першому масиві немає у другому?


1
Я впевнений, що вам потрібно пройти кожен елемент масивів.
Томас Лі

Чи знаєте ви, чому він повертає помилкове значення? Цікавий.
RobW

Див @ Андрій «s відповідь stackoverflow.com/a/6229263/702565
Carlos Precioso

Відповіді:


36
function arraysEqual(_arr1, _arr2) {

    if (!Array.isArray(_arr1) || ! Array.isArray(_arr2) || _arr1.length !== _arr2.length)
      return false;

    var arr1 = _arr1.concat().sort();
    var arr2 = _arr2.concat().sort();

    for (var i = 0; i < arr1.length; i++) {

        if (arr1[i] !== arr2[i])
            return false;

    }

    return true;

}

Зауважте, що це не змінює оригінальні масиви на відміну від попередньої відповіді.


2
сортування займає nlog (n) час. Вам не потрібно сортування. Ця відповідь stackoverflow.com/a/55614659/3209523 працює в лінійний час.
canbax

Використання машинопису Array.isArray () спричиняло помилки, видаляючи, що воно справно працює.
Аріель Фрішер

89

Якщо елементи масиву не є об'єктами - наприклад, це числа чи рядки, ви можете порівняти їх об'єднані рядки, щоб побачити, чи мають вони однакові члени в будь-якому порядку,

var array1= [10, 6, 19, 16, 14, 15, 2, 9, 5, 3, 4, 13, 8, 7, 1, 12, 18, 11, 20, 17];
var array2= [12, 18, 20, 11, 19, 14, 6, 7, 8, 16, 9, 3, 1, 13, 5, 4, 15, 10, 2, 17];

if(array1.sort().join(',')=== array2.sort().join(',')){
    alert('same members');
}
else alert('not a match');

2
Це буде добре працювати для примітивів або об'єктів, які мають унікальну ідентифікацію значень toString, але не для будь-яких об'єктів.
devios1

Дякую! акуратне рішення
Гастон Санчес

3
Остерігайтеся нульових предметів та сортування. Я закінчив у своєму випадку рядки для порівняння типу ", 2,2,3" та "2,2,3", які, звичайно, не є рівними.
barbara.post

2
Не вдалося отримати рядки, тобто ['a', 'b']і ['a,b']. Я рекомендував би цю техніку лише для невеликих сценаріїв, що викидаються.
alex

1
@alex - у моєму випадку коси дозволені в рядках, але напівколонки - ні, тому я використовував ';' щоб приєднатися замість коми
a2345сото

45

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

_.isEmpty(_.xor(array1, array2))

Короткий, простий і гарний!


1
Я не можу знайти xorв документах підкреслення? Ви думаєте про IODash?
Патрік Менчіас-левіс

44
Array.prototype.compare = function(testArr) {
    if (this.length != testArr.length) return false;
    for (var i = 0; i < testArr.length; i++) {
        if (this[i].compare) { //To test values in nested arrays
            if (!this[i].compare(testArr[i])) return false;
        }
        else if (this[i] !== testArr[i]) return false;
    }
    return true;
}

var array1 = [2, 4];
var array2 = [4, 2];
if(array1.sort().compare(array2.sort())) {
    doSomething();
} else {
    doAnotherThing();
}

Може бути?


Дякую! Це працює так, як бажано. Я трохи змінив функцію, щоб також міг знати, скільки є невідповідностей.
Карлос Пресіосо

хибно для [2,4] [4,2].
Сураз Ханал

@SurazKhanal Ще потрібно сортувати
Аарон

26

Чому ваш код не працював

У JavaScript є примітивні типи даних та непримітивні типи даних.

Для примітивних типів даних ==і ===перевірте, чи мають речі з обох боків брусків однакове значення. Ось чому 1 === 1правда.

Для непомітивних типів даних, таких як масиви, ==і ===перевірити рівність еталонів. Тобто, вони перевіряють , є чи arr1йarr2 є той самий об'єкт. У вашому прикладі два масиви мають однакові об’єкти в одному порядку, але не є рівнозначними.

Рішення

Два масиви, arr1і arr2, мають однакові члени, якщо і тільки якщо:

  • Все в arr2є вarr1

І

  • Все в arr1є вarr2

Отже, це зробить трюк (ES2016):

const containsAll = (arr1, arr2) => 
                arr2.every(arr2Item => arr1.includes(arr2Item))

const sameMembers = (arr1, arr2) => 
                        containsAll(arr1, arr2) && containsAll(arr2, arr1);

sameMembers(arr1, arr2); // `true`

Це друге рішення з використанням підкреслення ближче до того, що ви намагалися зробити:

arr1.sort();
arr2.sort();

_.isEqual(arr1, arr2); // `true`

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

Рішення вашого третього питання

Ви також запитували, як дізнатися, які речі arr1не містяться arr2.

Це зробить це (ES2015):

const arr1 = [1, 2, 3, 4];
const arr2 = [3, 2, 1];

arr1.filter(arr1Item => !arr2.includes(arr1Item)); // `[4]`

Ви також можете використати підкреслення difference: method:

_.difference(arr1, arr2); // `[4]`

ОНОВЛЕННЯ

Дивіться коментар @ Redu - це моє рішення sameMembers, але те, що ви можете мати на увазі, sameMembersInOrderтакож відоме deepEquals.

ОНОВЛЕННЯ 2

Якщо вам не байдуже порядок членів масивів, ES2015 + Setможе бути кращою структурою даних, ніж Array. Див. Примітки MDN про те, як реалізувати isSupersetтаdifference використовувати небезпечні виправлення мавп.


1
Ваші рішення неправильні. "Два масиви, arr1 і arr2, мають однакові члени, якщо і тільки якщо: Усе в arr2 є в arr1 І Все в arr1 є в arr2", це також неправильно. Це масив, а не набір. Тому sameMembers([1,1,2],[2,1,2]);слід повернути помилкове.
Скорочення

1
@Redu здогадуюсь, це залежить від того, що означає "ті ж члени" - я вважаю, що це "однакові члени". sameMembers([1,1,2],[2,1,2])повинен повернутися true, на мій погляд. sameMembersInOrder([1,1,2],[2,1,2])AKA deepEquals([1,1,2],[2,1,2])повинен повернутися false.
Макс Хайбер

Ваше третє рішення arr1.filter...буде працювати лише для перевірки того, що в arr2 є всі елементи arr1 чи ні, але не навпаки, який також необхідний.
Аакаш Верма

10

Перевірка рівності об'єкта:JSON.stringify(array1.sort()) === JSON.stringify(array2.sort())

Вищевказаний тест також працює з масивами об'єктів, і в цьому випадку використовується функція сортування, як це зафіксовано в http://www.w3schools.com/jsref/jsref_sort.asp

Можливо, достатньо для малих масивів з плоскими схемами JSON.


9

Наша мета в основному перевірити, чи 2 масиви рівні набори. множина - це математично визначений набір . Найшвидше сортування асимптотично займає час O (nlog (n)) . Отже, якщо ви сортуєте масив, це займе принаймні O (nlog (n)) час. Але ви можете виконати це завдання швидше , що асимптотично займає O (n) час (середній випадок, не гірший випадок) зі структурою даних словника. У JS словник - це просто об'єкт з ключами та значеннями.

/** assumes array elements are primitive types
* check whether 2 arrays are equal sets.
* @param  {} a1 is an array
* @param  {} a2 is an array
*/
function areArraysEqualSets(a1, a2) {
  const superSet = {};
  for (const i of a1) {
    const e = i + typeof i;
    superSet[e] = 1;
  }

  for (const i of a2) {
    const e = i + typeof i;
    if (!superSet[e]) {
      return false;
    }
    superSet[e] = 2;
  }

  for (let e in superSet) {
    if (superSet[e] === 1) {
      return false;
    }
  }

  return true;
}

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


5

Як що до цього? ES 2017 я гадаю:

const array1 = [1, 3, 5];
const array2 = [1, 5, 3];

const isEqual = (array1.length === array2.length) && (array1.every(val => array2.includes(val)));
console.log(isEqual);

Перша умова перевіряє, чи мають обидва масиви однакову довжину, а 2-а умова перевіряє, чи 1-й масив є підмножиною 2-го масиву. Поєднання цих 2 умов має призвести до порівняння всіх елементів 2 масивів незалежно від впорядкованості елементів.

Вищевказаний код працюватиме лише у тому випадку, якщо в обох масивах є не повторювані елементи.


3

Порівнюючи ці два масиви, ви порівнюєте об'єкти, які представляють масиви, а не вміст.

Вам доведеться використовувати функцію для порівняння двох. Ви можете написати власне, що просто циклічно, хоча одне, і порівняти його з іншим після того, як перевірите, чи довжини однакові.


3

Просте рішення для дрібної рівності за допомогою ES6:

const arr1test = arr1.slice().sort()
const arr2test = arr2.slice().sort()
const equal = !arr1test.some((val, idx) => val !== arr2test[idx])

Створює неглибокі копії кожного масиву та сортує їх. Потім використовує some()для перегляду arr1testзначень, перевіряючи кожне значення зі значенням у arr2testтому самому індексі. Якщо всі значення рівні, some()повертається false, а в свою чергу equalоцінюється до true.

Можливо також використовувати every(), але для задоволення trueрезультату доведеться проїхати кожен елемент масиву , тоді як some()буде порушено, як тільки знайде значення, яке не дорівнює:

const equal = arr1test.every((val, idx) => val === arr2test[idx])

2

Я мав прості цілі значення в ігровому проекті.
У кожному масиві була менша кількість значень. Також потрібен був той недоторканий оригінальний масив.
Отже, я зробив нижче, він працював чудово. (Код відредагований для вставки тут)

var sourceArray = [1, 2, 3];
var targetArray = [3, 2, 1];

if (sourceArray.length !== targetArray.length) {
    // not equal
    // did something
    return false;
}

var newSortedSourceArray = sourceArray.slice().sort();
var newSortedTargetArray = targetArray.slice().sort();

if (newSortedSourceArray.toString() !== newSortedTargetArray.toString()) { // MAIN CHECK
    // not equal
    // did something
    return false;
}
else {
    // equal
    // did something
    // continued further below
}

// did some more work

return true;

Сподіваюся, що це допомагає.


2

Використання ES6

Ми будемо використовувати функцію Ramda equals, але замість цього ми можемо використовувати Лодаша або Підкреслення isEqual:

const R = require('ramda');

const arraysHaveSameValues = (arr1, arr2) => R.equals( [...arr1].sort(), [...arr2].sort() )

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


2

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

function isArrayContentSame(a, b) {
  if (Array.isArray(a) && Array.isArray(b) && a.length == b.length) {
    a = a.concat().sort()
    b = b.concat().sort()
    return a.reduce((acc,e,i) => acc && e === b[i], true)
  } else {
    return false;
  }
}

1

Якщо об'єкти в масиві є примітивами (числами або окремими символами), ви можете використовувати комбінацію порівняння довжин та використання наборів.

function equalArrayItems(arr1, arr2) {
  if (arr1.length !== arr2.length) return false
  const set1 = new Set(arr1)
  const set2 = new Set(arr2)
  const set3 = new Set(arr1, arr2)
  return set1.size === set3.size && set2.size === set3.size
}

1

Вже 2020 рік, але я помітив, що більшість інших рішень використовують сортування, O (n * log n), використовують бібліотеки або мають складність O (n ^ 2).

Ось чисте рішення Javascript з лінійною складністю, O (n):

/**
 * Check if two arrays of strings or numbers have the same values regardless of the order
 * @param {string[]|number[]} arr1
 * @param {string[]|number[]} arr2
 * @return {boolean}
 */    
compareArrays = (arr1, arr2) => {
    if (arr1.length !== arr2.length) return false;
    const lk1 = {};
    const lk2 = {};
    let i = arr1.length;
    while (--i >= 0) {
        lk1[arr1[i]] = true;
        lk2[arr2[i]] = true
    }
    i = arr1.length;
    while (--i >= 0) {
        const v = arr1[i];
        if (lk1[v] !== lk2[v]) return false;
    }
    return true
}

Тести:

compareArrays([2, 4], [4, 2]) => true
compareArrays([2, 4], [4, 2, 7]) => false
compareArrays([], []) => true

1
Гей, це дивовижний запис! Це доволі перекручено, але це має сенс. У мене питання: я не дуже знайомий з нотацією Big O, але, безумовно, цей алгоритм є O (2n)? Не думайте, що це дуже має значення.
Карлос Пресіосо

1
@CarlosPrecioso Це правильно і O (2n) = O (n). Складність не змінюється множенням на постійний коефіцієнт
SC1000

0

Якщо ви використовуєте Prototype Framework, ви можете використовувати метод перетину масиву, щоб дізнатися, чи вони однакові (незалежно від порядку):

var array1 = [1,2];
var array2 = [2,1];

if(array1.intersect(array2).length === array1.length) {
    alert("arrays are the same!");
}

Це не працює - [1,2].intersect([1,2,3]).length === [1,2].lengthповертає істину. Ви також повинні порівняти довжину початкових масивів, я редагував публікацію, щоб продемонструвати.
GMA

Насправді я щойно зрозумів, що запропонована нами редакція не працює у випадку дублікатів ... наприклад, вона поверне помилкову для array1 = [1,1,2]; array2 = [1,1,2];... оригінальна відповідь не провалюється для цього вводу.
GMA

Можна зробити те саме_.difference(array1, array2).length;
Вік,

0

люб’язно перевірте цю відповідь

var arr1= [12,18];
var arr2= [12, 18, 20, 11, 19, 14, 6, 7, 8, 16, 9, 3, 1, 13, 5, 4, 15, 10, 2, 17];
for(i=0;i<arr1.length;i++)
{
var array1=arr1[i];
for(j=0;j<arr2.length;j++)
{
    var array2=arr2[j];
    if(array1==array2)
    {
return true;
    }
}
}

2
Це функціонально еквівалентно цій відповіді , за винятком пари помилок. По-перше, все це повинно бути зафіксовано у функції, returnінакше воля не матиме ефекту. По- друге, ви повинні перевірити , відсортовані масиви, так [1,2]і [2,1]буде виявлений як не те ж саме. По-третє, і найважливіше, це насправді лише перевірятиме, чи якийсь елемент однаковий. Умовна повинна бути if (array1!==array2) {return false;}. Можливо, це може допомогти вам у майбутньому!
Карлос Пресіосо

1
І як додатковий коментар, намагайтеся використовувати відступи для кращого розуміння потоку коду, а також більш чіткі назви змінних. Наприклад: array1і array2може бути перейменований elem1і elem2. Обидві ці поради позбавлять вас від багатьох головних болів у майбутньому!
Карлос Пресіосо

2
При подальшому огляді, чому подвійний цикл? Обидва масиви повинні бути однакової довжини, а якщо ні, то вони безпосередньо не рівні. Таким чином ви можете використовувати лише одну петлю. Зараз цей код перевіряє, чи будь-який з елементів першого масиву знаходиться десь у другому. Перевірте цю відповідь, щоб побачити, як слід її реалізувати. Успіхів вам у подорожі JavaScript!
Карлос Пресіосо

0

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

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

Ви можете використовувати перехрестя з бібліотеки lodash.

_.intersection(['2-1', '1'], ['2-2', '3-1', '2-1']); 
// => ['2-1']

Це буде працювати для будь-якого типу даних ..


0

Якщо ви хочете порівняти два масиви і перевірити, чи будь-який об’єкт однаковий в обох масивах, він буде працювати. Приклад:

Масив1 = [a, b, c, d]
Array2 = [d, e, f, g]

Тут 'd' є загальним для обох масивів, тому ця функція поверне справжнє значення.

  cehckArray(array1, array2) {
    for (let i = 0; i < array1.length; i++) {
      for (let j = 0; j < array2.length; j++) {
        if (array1[i] === array2[j]) {
          return true;
        }
      }
    }
    // Return if no common element exist 
    return false;
  }

0

Спробуйте це

function arraysEqual(arr1, arr2){
    if (!Array.isArray(arr1) || !Array.isArray(arr2) || arr1.length!=arr2.length)
        return false;

    return arr1.length==arr1.filter(word => arr2.includes(word)).length;
}

0

У мене є інший спосіб, заснований на прийнятій відповіді.

function compareArrays(array1, array2) {

    if (
        !Array.isArray(array1)
        || !Array.isArray(array2)
        || array1.length !== array2.length
    ) return false;

    var first = array1.sort().map(value => (String(value))).join();
    var second = array2.sort().map(value => (String(value))).join();

    return first == second ? true : false;
}

Привіт, ласкаво просимо до StackOverflow! Хоча ця відповідь спрацювала б у деяких випадках, були б певні конкретні випадки, коли цього не було б. Спочатку майте на увазі, що .sort () модифікує вихідний масив. Сьогодні це вважається поганою гігієною, тому первісна відповідь спочатку робить .concat (), щоб зробити копію.
Карлос Пресіосо

І другий момент, це не працює послідовно з рештою JavaScript. {foo: "bar"} === {foo: "bar"} повертає помилкові (це два різних об'єкти, створені окремо); тому порівняйтеArrays ([{foo: "bar"}], [{foo: "bar"}]), також слід повернути помилкові для послідовності. Однак при вашій реалізації вона повертає істину, оскільки рядкове представлення об'єктів однакове. Це може бути бажана поведінка, чи ні, але слід пам’ятати в будь-якому випадку.
Карлос Пресіосо

0

Функція для порівняння двох масивів, щоб перевірити, чи є в обох однакові елементи. Навіть якщо вони вийшли з ладу ...

Це добре для простих масивів. [Рядок, число, булева, null, NaN].

Я не використовую .sort (), він змінює вихідний масив. Деякі кажуть, що це погано ...

Обережність. Ця функція обмежена, вона не може порівнювати об'єкти "[], {}" або функції в цих масивах, масиви, які "я" - це "об'єкти".

   let arraysHasSameElements = (arr1, arr2) => {
        let count =
            // returns counting of occurrences.
            (arr, val) => arr.reduce((count, curr) => (curr === val ? 1 : 0) + count, 0);

        /* this will return true if lengths of the arrays is equal.
           then compare them.*/
        return arr1.length === arr2.length

            // compare arr1 against arr2.
            && arr1.reduce((checks, val) =>

                /*  creating array of checking if a value has equal amount of occurrences
                    in both arrays, then adds true 'check'. */
                checks.concat(count(arr1, val) === count(arr2, val)), [])

                // checking if each check is equal to true, then .every() returns true.
                .every(check => check);
    }

    let arr1 = ['',-99,true,NaN,21,null,false,'help',-99,'help',NaN], 
        arr2 = [null,-99,'',NaN,NaN,false,true,-99,'help',21,'help'];
    arraysHasSameElements(arr1, arr2); //true

    let arr3 = [false,false,false,false,false,false], 
        arr4 = [false,false,false,false,false,false]
    arraysHasSameElements(arr3, arr4); //true


    // here we have uncommented version.
    let arraysHasSameElements = (arr1, arr2) => {
        let count = (arr, val) => arr.reduce((count, curr) => (curr === val ? 1:0) + count, 0);
        return arr1.length === arr2.length && arr1.reduce((checks, val) =>
            checks.concat(count(arr1, val) === count(arr2, val)), []).every(check => check);
    }

-1

Просте рішення для порівняння двох масивів:

var array1 = [2, 4];
var array2 = [4, 2];

array1.sort();
array2.sort();

if (array1[0] == array2[0]) {
    console.log("Success");
}else{
    console.log("Wrong");
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.