Come sapere se due array hanno gli stessi valori


104

Ho questi due array: uno è pieno di informazioni da una richiesta ajax e un altro memorizza i pulsanti su cui l'utente fa clic. Uso questo codice (ho inserito i numeri di esempio):

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

Ma dà sempre false, anche se i due array sono uguali, ma con un nome diverso. (L'ho controllato nella console JS di Chrome). Quindi, c'è un modo per sapere se questi due array contengono lo stesso? Perché sta dando false? Come posso sapere quali valori nel primo array non sono nel secondo?


1
Sono abbastanza certo che sia necessario esaminare ogni elemento degli array.
Thomas Li

Sai perché restituisce falso? Curioso.
RobW


Risposte:


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;

}

Nota che questo non modifica gli array originali a differenza di una risposta precedente.


2
l'ordinamento richiede nlog (n) tempo. Non hai bisogno di smistamento. Questa risposta stackoverflow.com/a/55614659/3209523 funziona in tempo lineare.
canbax

Utilizzando il dattiloscritto, Array.isArray () causava errori, rimuovendo che funzionava bene.
Ariel Frischer

88

Se gli elementi dell'array non sono oggetti, ad esempio se sono numeri o stringhe, puoi confrontare le loro stringhe unite per vedere se hanno gli stessi membri in qualsiasi ordine

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
Questo funzionerà bene per le primitive o gli oggetti che hanno valori di identificazione in modo univoco toString, ma non solo per qualsiasi oggetto.
devios1

Grazie! soluzione pulita
Gaston Sanchez

3
Attenzione agli elementi nulli e all'ordinamento. Nel mio caso sono finito con stringhe da confrontare come ", 2,2,3" e "2,2,3", che ovviamente non sono strettamente uguali.
barbara.post

2
Potrebbe fallire per le stringhe, cioè ['a', 'b']e ['a,b']. Consiglierei questa tecnica solo per piccoli script usa e getta.
alex

1
@alex - nel mio caso, le virgole sono consentite nelle stringhe ma i punti e virgola no, quindi ho usato ';' per unirsi al posto della virgola
a2345sooted

45

Se vuoi controllare solo se due array hanno gli stessi valori (indipendentemente dal numero di occorrenze e dall'ordine di ogni valore) puoi farlo usando lodash :

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

Breve, semplice e carino!


1
Non riesco a trovare xornella sottolineatura i documenti? Stai pensando a IODash?
Patrick Mencias-lewis

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

Può essere?


Grazie! Funziona proprio come desiderato. Ho modificato un po 'la funzione in modo da poter anche sapere quante mancate corrispondenze sono.
Carlos Precioso

falso per [2,4] [4,2].
Suraz Khanal

@ SurazKhanal Ancora bisogno di ordinare
Aaron McMillin

26

Perché il tuo codice non ha funzionato

JavaScript ha tipi di dati primitivi e tipi di dati non primitivi.

Per i tipi di dati primitivi ==e ===controlla se le cose su entrambi i lati delle barre hanno lo stesso valore. Ecco perché 1 === 1è vero.

Per i tipi di dati non primitivi come gli array ==e ===verifica l'uguaglianza dei riferimenti. Cioè, controllano se arr1e arr2sono lo stesso oggetto. Nel tuo esempio, i due array hanno gli stessi oggetti nello stesso ordine, ma non sono equivalenti.

soluzioni

Due array arr1e arr2hanno gli stessi membri se e solo se:

  • Tutto dentro arr2è dentroarr1

E

  • Tutto dentro arr1è dentroarr2

Quindi questo farà il trucco (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`

Questa seconda soluzione che utilizza il carattere di sottolineatura è più vicina a ciò che stavi cercando di fare:

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

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

Funziona perché isEqualverifica "l'uguaglianza profonda", il che significa che non si limita a considerare l'uguaglianza dei riferimenti e confronta i valori.

Una soluzione alla tua terza domanda

Hai anche chiesto come scoprire in quali cose arr1non sono contenute arr2.

Questo lo farà (ES2015):

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

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

Puoi anche usare il differencemetodo del carattere di sottolineatura ::

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

AGGIORNARE

Vedi il commento di @ Redu: la mia soluzione è per sameMembers, ma ciò che potresti avere in mente è sameMembersInOrderanche noto come deepEquals.

AGGIORNAMENTO 2

Se non ti interessa l'ordine dei membri degli array, ES2015 + Setpotrebbe essere una struttura dati migliore di Array. Vedere le note MDN su come implementare isSupersetedifference utilizzare pericolose patch di scimmia.


1
Le tue soluzioni sono sbagliate. "Due array, arr1 e arr2, hanno gli stessi membri se e solo se: Tutto in arr2 è in arr1 E Tutto in arr1 è in arr2" anche questo è sbagliato. Questo è un array, non un set. Quindi sameMembers([1,1,2],[2,1,2]);dovrebbe restituire falso.
Redu

1
@Redu immagino che dipenda da cosa significa "stessi membri", credo che significhi "ha gli stessi membri". sameMembers([1,1,2],[2,1,2])dovrebbe tornare true, secondo me. sameMembersInOrder([1,1,2],[2,1,2])AKA deepEquals([1,1,2],[2,1,2])dovrebbe tornare false.
Max Heiber

La terza soluzione arr1.filter...funzionerà solo per verificare se arr2 ha tutti gli elementi di arr1 o meno, ma non il contrario che è richiesto.
Aakash Verma

9

Controllo dell'uguaglianza degli oggetti:JSON.stringify(array1.sort()) === JSON.stringify(array2.sort())

Il test di cui sopra funziona anche con array di oggetti, nel qual caso usa una funzione di ordinamento come documentato in http://www.w3schools.com/jsref/jsref_sort.asp

Potrebbe essere sufficiente per piccoli array con schemi JSON piatti.


9

Il nostro scopo è fondamentalmente verificare se 2 array sono insiemi uguali. set è l' insieme definito matematicamente . L'ordinamento più veloce in modo asintotico richiede tempo O (nlog (n)) . Quindi, se si ordina un array, ci vorrà almeno O (nlog (n)) tempo. Ma puoi eseguire questa operazione più velocemente , il che richiede asintoticamente O (n) tempo (caso medio non caso peggiore) con una struttura dati del dizionario. In JS, un dizionario è semplicemente un oggetto con chiavi e valori.

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

Si noti che questa funzione funziona con array di tipi primitivi e presuppone a1e a2siano array.


5

Che dire di questo? ES 2017 suppongo:

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

La prima condizione controlla se entrambi gli array hanno la stessa lunghezza e la seconda condizione controlla se il primo array è un sottoinsieme del secondo array. La combinazione di queste 2 condizioni dovrebbe quindi risultare in un confronto di tutti gli elementi dei 2 array indipendentemente dall'ordinamento degli elementi.

Il codice precedente funzionerà solo se entrambi gli array hanno elementi non duplicati.


3

Quando confronti questi due array, stai confrontando gli oggetti che rappresentano gli array, non il contenuto.

Dovrai usare una funzione per confrontare i due. Potresti scrivere il tuo che semplicemente si ripete l'uno e lo confronta con l'altro dopo aver verificato che le lunghezze siano le stesse.


3

Soluzione semplice per l'uguaglianza superficiale utilizzando ES6:

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

Crea copie superficiali di ogni array e le ordina. Quindi utilizza some()per scorrere i arr1testvalori, controllando ogni valore rispetto al valore arr2testcon lo stesso indice. Se tutti i valori sono uguali, some()i rendimenti false, ed a sua volta equalrestituisce true.

Potrebbe anche usare every(), ma dovrebbe scorrere ogni elemento nell'array per soddisfare un truerisultato, mentre some()verrà salvato non appena trova un valore diverso da quello:

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

2

Avevo valori interi semplici in un progetto di gioco
Avevo un numero inferiore di valori in ogni array, inoltre
, avevo bisogno di quell'array originale intatto Quindi, ho fatto quanto segue, ha funzionato bene. (Codice modificato per incollare qui)

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;

Spero che aiuti.


2

Utilizzando ES6

Useremo la equalsfunzione di Ramda , ma invece possiamo usare Lodash o Underscore isEqual:

const R = require('ramda');

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

Utilizzando lo spread opporator, evitiamo di modificare gli array originali e manteniamo pura la nostra funzione.


2

Puoi usare reduceinvece dei loop per sembrare intelligente, ma con il rischio che i tuoi colleghi sviluppatori ti considerino un idiota.

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

Se gli elementi nell'array sono primitivi (numeri o singoli caratteri), è possibile utilizzare una combinazione di confronto delle lunghezze e utilizzo di set.

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

È già il 2020 ma ho notato che la maggior parte delle altre soluzioni usa sort, O (n * log n), usa librerie o ha complessità O (n ^ 2).

Ecco una soluzione Javascript pura con complessità lineare, 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
}

test:

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

1
Ehi, è una voce fantastica! È abbastanza contorto ma ha senso. Ho una domanda: non ho molta familiarità con la notazione Big O, ma sicuramente questo algoritmo è O (2n)? Non credo che questo faccia molta differenza.
Carlos Precioso

1
@CarlosPrecioso Esatto e O (2n) = O (n). La complessità non cambia moltiplicandosi per un fattore costante
SC1000

0

Se stai usando Prototype Framework, puoi usare il metodo intersect di un array per scoprire che sono uguali (indipendentemente dall'ordine):

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

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

Questo non funziona - [1,2].intersect([1,2,3]).length === [1,2].lengthrestituisce true. Dovresti confrontare anche la lunghezza degli array originali, ho modificato il post per dimostrarlo.
GMA

In realtà mi sono appena reso conto che la mia modifica suggerita non funziona in caso di duplicati ... ad es. Restituirà false per array1 = [1,1,2]; array2 = [1,1,2];... la risposta originale non fallisce per quell'input.
GMA

Puoi fare il contrario con_.difference(array1, array2).length;
Vic

0

si prega di controllare questa risposta

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
Questo è funzionalmente equivalente a questa risposta , salvo un paio di errori. Innanzitutto, dovrebbe essere tutto racchiuso in una funzione, altrimenti returnnon avrà alcun effetto. In secondo luogo, dovresti controllare gli array ordinati, poiché [1,2]e [2,1]verranno rilevati come non uguali. Terzo e più importante, questo controllerà solo se qualche elemento è lo stesso. Il condizionale dovrebbe essere if (array1!==array2) {return false;}. Forse questo può aiutarti in futuro!
Carlos Precioso

1
E come commento aggiuntivo, prova a utilizzare l'indentazione per una migliore comprensione del flusso di codice, oltre a nomi di variabili più chiari. Ad esempio: array1e array2potrebbe essere rinominato elem1e elem2. Entrambi questi suggerimenti ti faranno risparmiare un sacco di mal di testa in futuro!
Carlos Precioso

2
A un ulteriore esame, perché il doppio anello? Entrambi gli array dovrebbero avere la stessa lunghezza e, in caso contrario, non sono direttamente uguali. In questo modo puoi usare un solo loop. In questo momento, questo codice controlla se qualcuno degli elementi del primo array si trova in un punto qualsiasi del secondo. Controlla questa risposta per vedere come dovresti implementarla. Buona fortuna per il tuo viaggio in JavaScript!
Carlos Precioso

0

Rispondere dopo molto tempo, ma spero che questo possa aiutare qualcuno che cerca una soluzione semplice e neofiti moderni.

Ora siamo in grado di ottenere questo utilizzando librerie multiple come lodash, underscoree così via (questi entra a far parte del progetto oggi a causa semplicità, funzionalità multiple e un utilizzo elevato)

Puoi usare l'intersezione dalla libreria lodash.

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

Funzionerà per qualsiasi tipo di dati ..


0

Se vuoi confrontare due array e controllare se un oggetto è uguale in entrambi gli array, funzionerà. Esempio :

Array1 = [a, b, c, d]
Array2 = [d, e, f, g]

Qui, 'd' è comune in entrambi gli array, quindi questa funzione restituirà il valore vero.

  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

Prova questo

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

Ho un altro modo basato sulla risposta accettata.

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

Ehi, benvenuto in StackOverflow! Sebbene questa risposta funzionerebbe in alcuni casi, ci sarebbero alcuni casi specifici in cui non funzionerebbe. Prima di tutto, tieni presente che .sort () modifica l'array originale. Al giorno d'oggi è considerata scarsa igiene, ecco perché la risposta originale fa prima un .concat (), per fare una copia.
Carlos Precioso

E secondo punto, questo non funzionerebbe in modo coerente con il resto di JavaScript. {foo: "bar"} === {foo: "bar"} restituisce false (sono due oggetti distinti creati separatamente); quindi compareArrays ([{foo: "bar"}], [{foo: "bar"}]), dovrebbe anche restituire false per coerenza. Tuttavia, con l'implementazione, restituisce true, poiché la rappresentazione di stringa degli oggetti è la stessa. Potrebbe essere un comportamento desiderato o no, ma di cui essere consapevoli in ogni caso.
Carlos Precioso

0

Una funzione per confrontare due array, per verificare se entrambi hanno gli stessi elementi. Anche se sono fuori servizio ...

Va bene per array semplici. [String, numero, booleano, null, NaN].

Non uso .sort (), modifica l'array originale. Alcuni dicono che è brutto ...

Attenzione. Questa funzione è limitata e non può confrontare Oggetti "[], {}" o funzioni all'interno di questi Array, gli array in sé sono Oggetti.

   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

Soluzione semplice per confrontare i due array:

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

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

if (array1[0] == array2[0]) {
    console.log("Success");
}else{
    console.log("Wrong");
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.