Come confrontare le matrici in JavaScript?


991

Vorrei confrontare due array ... idealmente, in modo efficiente. Niente di speciale, solo truese sono identici e in falsecaso contrario. Non sorprende che l'operatore di confronto non sembra funzionare.

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

Codifica JSON per ciascun array, ma esiste un modo più veloce o "migliore" per confrontare semplicemente gli array senza dover scorrere ogni valore?


5
Puoi prima confrontare la loro lunghezza e se sono uguali per ogni valore.
TJHeuvel,

56
Cosa rende uguali due array per te? Stessi elementi? Stesso ordine di elementi? La codifica come JSON funziona solo finché l'elemento dell'array può essere serializzato su JSON. Se l'array può contenere oggetti, quanto approfondiresti? Quando due oggetti sono "uguali"?
Felix Kling,

48
@FelixKling, definire "uguaglianza" è sicuramente un argomento sottile, ma per le persone che arrivano a JavaScript da linguaggi di livello superiore, non ci sono scuse per stupidità come ([] == []) == false.
Alex D

4
@AlexD sembra che gli array utilizzino l'uguaglianza di riferimento che è quello che ti aspetteresti. Sarebbe piuttosto terribile se non ci
riuscissi

3
@AlexD Non riesco a pensare a una lingua in cui ciò non accada. In C ++, confronteresti due puntatori: falso. In Java, stai facendo lo stesso di JavaScript. In PHP, qualcosa dietro le quinte scorre ciclicamente attraverso gli array: chiami PHP un linguaggio di livello superiore?
Tomáš Zato - Ripristina Monica il

Risposte:


877

Per confrontare le matrici, scorrere in sequenza e confrontare tutti i valori:

Confronto di array:

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

Uso:

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

Puoi dire " Ma è molto più veloce confrontare le stringhe - nessun loop ... " bene, allora dovresti notare che ci sono loop. Primo ciclo ricorsivo che converte Array in stringa e secondo, che confronta due stringhe. Quindi questo metodo è più veloce dell'uso della stringa .

Credo che grandi quantità di dati debbano essere sempre archiviate in array, non in oggetti. Tuttavia, se si utilizzano oggetti, è possibile confrontarli parzialmente.
Ecco come:

Confronto di oggetti:

Ho affermato sopra, che due istanze di oggetto non saranno mai uguali, anche se al momento contengono gli stessi dati:

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

Questo ha una ragione, poiché potrebbero esserci, ad esempio, variabili private all'interno degli oggetti.

Tuttavia, se si utilizza semplicemente la struttura degli oggetti per contenere i dati, il confronto è ancora possibile:

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

Tuttavia, ricorda che questo serve a confrontare i dati simili a JSON, non le istanze di classe e altre cose. Se vuoi confrontare oggetti più complicati, guarda questa risposta ed è una funzione molto lunga .
Per farlo funzionare con Array.equalste devi modificare un po 'la funzione originale:

...
    // 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]) {
...

Ho realizzato un piccolo strumento di test per entrambe le funzioni .

Bonus: array nidificati con indexOfecontains

Samy Bencherif ha preparato funzioni utili per il caso in cui stai cercando un oggetto specifico in array nidificati, disponibili qui: https://jsfiddle.net/SamyBencherif/8352y6yw/


27
Se vuoi fare confronti severi usa this[i] !== array[i]invece di !=.
Tim S.

38
Il tuo metodo dovrebbe essere chiamato equalsinvece di compare. Almeno in .NET, compare di solito restituisce un int firmato che indica quale oggetto è maggiore dell'altro. Vedi: Comparer.Compare .
Oliver,

15
Non è solo questo il modo giusto di farlo, è anche molto più efficace. Ecco un breve script jsperf che ho preparato per tutti i metodi suggeriti in questa domanda. jsperf.com/comparing-arrays2
Tolga E

96
Cambiare il prototipo di un tipo incorporato non è sicuramente il modo giusto
Jasper,

31
Inoltre, non si tratta di riscrivere facilmente, si tratta del fatto che una risposta non dovrebbe raccomandare qualcosa che è considerato una cattiva pratica ( developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/… ) e dovrebbe sicuramente non farlo sotto l'intestazione "La strada giusta"
Jasper,

386

Mentre questo funziona solo per array scalari (vedi nota sotto), è breve:

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

Rr, in ECMAScript 6 / CoffeeScript / TypeScript con funzioni freccia:

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

(Nota: 'scalare' qui significa valori che possono essere confrontati direttamente usando ===. Quindi: numeri, stringhe, oggetti per riferimento, funzioni per riferimento. Vedere il riferimento MDN per maggiori informazioni sugli operatori di confronto).

AGGIORNARE

Da quello che ho letto dai commenti, l'ordinamento dell'array e il confronto possono dare risultati accurati:

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

Per esempio:

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

Quindi darebbe il codice sopra true


19
Mi piace, anche se i lettori dovrebbero essere consapevoli che questo funziona solo su array ordinati.
Ellen Spertus,

13
Funziona su qualsiasi tipo di array, ordinato o no @espertus
Michał Miszczyszyn

36
Si, esattamente. Questa funzione dovrebbe confrontare due array, non importa se sono ordinati o no, i loro elementi consecutivi devono essere uguali.
Michał Miszczyszyn,

22
@espertus In effetti, non tornerà vero se gli elementi non hanno lo stesso ordine esatto in entrambi gli array. Tuttavia, l'obiettivo di un controllo di uguaglianza non è verificare se contengono gli stessi elementi, ma verificare se hanno lo stesso elemento negli stessi ordini.
Quentin Roy,

7
Se si desidera verificare se entrambi gli array sono uguali, contenenti gli stessi elementi non ordinati (ma non utilizzati più volte), è possibile utilizzare 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];non funzionerà come previsto)
mems

208

Mi piace usare la libreria Underscore per progetti di codifica pesante di array / oggetti ... in Underscore e Lodash, sia che si stiano confrontando array o oggetti, è proprio così:

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

22
Nota che l'ordine conta _.isEqual([1,2,3], [2,1,3]) => false
Vitaliy Alekask,

3
o se vuoi solo la isEqualfunzionalità, puoi sempre usare il modulo
lodash.isequal

6
Puoi forse usare _.difference (); se l'ordine non ti interessa
Ronan Quillevere

5
È possibile ordinare l'array prima di questo controllo se l'ordine non ha importanza_.isEqual([1,2,3].sort(), [2,1,3].sort()) => true
digitare il

risposta più concisa e diretta IMHO :-)
Kieran Ryan il

121

Questo penso sia il modo più semplice per farlo usando JSON stringify, e potrebbe essere la soluzione migliore in alcune situazioni:

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

Questo converte gli oggetti a1e le a2stringhe in modo che possano essere confrontati. L'ordine è importante nella maggior parte dei casi, poiché può ordinare l'oggetto usando un algoritmo di ordinamento mostrato in una delle risposte sopra.

Si noti che non si sta più confrontando l'oggetto ma la rappresentazione di stringa dell'oggetto. Potrebbe non essere esattamente quello che vuoi.


buona risposta ma perché [] == [] restituisce false? entrambi sono oggetti semplici, allora perché?
Pardeep Jain,

4
@PardeepJain, questo perché, per impostazione predefinita, l'operatore di uguaglianza in ECMAScript for Objects restituisce true quando fanno riferimento alla stessa posizione di memoria. Prova var x = y = []; // ora l'uguaglianza ritorna vera.
Radtek,

7
solo per notare che la funzione stringify JSON non è veloce. Utilizzato con array più grandi introdurrà sicuramente il ritardo.
Lukas Liesis,

6
La domanda in particolare chiede se esiste un modo migliore / più veloce rispetto all'utilizzo di JSON.stringify.
Don Hatch,

Si entra in maggior dettaglio sul perché questa potrebbe essere una buona soluzione per alcune situazioni.
Radtek,

61

Non è chiaro cosa intendi con "identico". Ad esempio, le matrici ae bsotto sono identiche (notare le matrici nidificate)?

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

Ecco una funzione di confronto di array ottimizzata che confronta gli elementi corrispondenti di ciascun array a sua volta usando una rigorosa uguaglianza e non fa un confronto ricorsivo di elementi di array che sono essi stessi array, il che significa che per l'esempio precedente, arraysIdentical(a, b)ritornerebbe false. Funziona nel caso generale, che le join()soluzioni JSON e basate su:

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: Non è chiaro dalla domanda cosa significhi "identico". Ovviamente questa risposta fa solo un controllo superficiale. Aggiungerò una nota.
Tim Down

questo fallisce per gli arrayIdentical ([1, 2, [3, 2]], [1, 2, [3, 2]]);
Gopinath Shiva,

4
@GopinathShiva: Beh, fallisce solo se ti aspetti che ritorni true. La risposta spiega che non lo farà. Se è necessario confrontare array nidificati, è possibile aggiungere facilmente un controllo ricorsivo.
Tim Down

59

Il modo pratico

Penso che sia sbagliato dire che una particolare implementazione è "The Right Way ™" se è solo "giusta" ("corretta") in contrasto con una soluzione "sbagliata". La soluzione di Tomáš è un netto miglioramento rispetto al confronto di array basato su stringhe, ma ciò non significa che sia oggettivamente "giusta". Cosa è giusto comunque? È il più veloce? È il più flessibile? È il più facile da capire? È il debug più veloce? Utilizza le meno operazioni? Ha effetti collaterali? Nessuna soluzione può avere il meglio di tutte le cose.

Tomáš potrebbe dire che la sua soluzione è veloce, ma direi anche che è inutilmente complicata. Cerca di essere una soluzione all-in-one che funziona per tutti gli array, nidificati o meno. In effetti, accetta anche più di una semplice matrice come input e tenta comunque di fornire una risposta "valida".


I generici offrono riusabilità

La mia risposta affronterà il problema in modo diverso. Inizierò con una arrayCompareprocedura generica che riguarda solo il passaggio attraverso le matrici. Da lì, costruiremo le nostre altre funzioni di confronto di base come arrayEquale arrayDeepEqual, ecc

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

Secondo me, il miglior tipo di codice non ha nemmeno bisogno di commenti, e questa non fa eccezione. Qui sta succedendo così poco che puoi capire il comportamento di questa procedura quasi senza alcuno sforzo. Certo, alcune sintassi di ES6 potrebbero sembrarti estranee adesso, ma questo è solo perché ES6 è relativamente nuovo.

Come suggerisce il tipo, arrayCompareaccetta la funzione di confronto fe due array di input xse ys. Per la maggior parte, tutto ciò che facciamo è chiamare f (x) (y)ogni elemento negli array di input. Restituiamo in anticipo falsese i fresi definiti dall'utente false- grazie alla &&valutazione del corto circuito. Quindi sì, questo significa che il comparatore può interrompere l'iterazione in anticipo e impedire il loop attraverso il resto dell'array di input quando non è necessario.


Confronto rigoroso

Successivamente, utilizzando la nostra arrayComparefunzione, possiamo facilmente creare altre funzioni di cui potremmo avere bisogno. Inizieremo con l'elementare 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

Semplice come quella. arrayEqualpuò essere definito con arrayComparee una funzione di confronto che si confronta acon l' butilizzo ===(per una rigorosa uguaglianza).

Si noti che definiamo anche equalcome propria funzione. Ciò evidenzia il ruolo di arrayCompareuna funzione di ordine superiore per utilizzare il nostro comparatore di primo ordine nel contesto di un altro tipo di dati (Array).


Confronto sciolto

Potremmo definire altrettanto facilmente arrayLooseEqualusando un ==invece. Ora confrontando 1(Numero) con '1'(Stringa), il risultato sarà 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

Confronto profondo (ricorsivo)

Probabilmente avrai notato che questo è solo un confronto superficiale. Sicuramente la soluzione di Tomáš è "The Right Way ™" perché implica un confronto profondo implicito, giusto?

Bene, la nostra arrayCompareprocedura è abbastanza versatile da usare in un modo che rende un test di uguaglianza profonda un gioco da ragazzi ...

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

Semplice come quella. Costruiamo un comparatore profondo usando un'altra funzione di ordine superiore. Questa volta stiamo eseguendo il wrapping arrayCompareutilizzando un comparatore personalizzato che controllerà se ae bsono array. In tal caso, riapplica arrayDeepComparealtrimenti confronta ae bal comparatore specificato dall'utente ( f). Questo ci consente di mantenere il comportamento di confronto profondo separato dal modo in cui confrontiamo effettivamente i singoli elementi. Cioè, come nell'esempio qui sopra, si può confrontare profondo utilizzando equal, looseEqualo qualsiasi altro comparatore facciamo.

Perché arrayDeepCompareè curry, possiamo parzialmente applicarlo come abbiamo fatto anche negli esempi precedenti

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

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

Per me, questo è già un chiaro miglioramento rispetto alla soluzione di Tomáš perché posso esplicitamente scegliere un confronto superficiale o profondo per i miei array, se necessario.


Confronto oggetti (esempio)

E se avessi una serie di oggetti o qualcosa del genere? Forse vuoi considerare quegli array come "uguali" se ogni oggetto ha lo stesso idvalore ...

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

Semplice come quella. Qui ho usato oggetti JS alla vaniglia, ma questo tipo di comparatore potrebbe funzionare per qualsiasi tipo di oggetto; anche i tuoi oggetti personalizzati. La soluzione di Tomáš dovrebbe essere completamente rielaborata per supportare questo tipo di test di uguaglianza

Array profondo con oggetti? Non è un problema. Abbiamo creato funzioni generiche molto versatili, quindi funzioneranno in un'ampia varietà di casi d'uso.

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

Confronto arbitrario (esempio)

O se volessi fare qualche altro tipo di confronto completamente arbitrario? Forse voglio sapere se ognuno xè maggiore di ogni 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

Meno è meglio

Puoi vedere che stiamo effettivamente facendo di più con meno codice. Non c'è nulla di complicato su arrayComparese stesso e ciascuno dei comparatori personalizzati che abbiamo realizzato ha un'implementazione molto semplice.

Con facilità, possiamo definire esattamente come desideriamo due matrici per essere confrontati - superficiale, profondo, rigoroso, sciolto, alcune proprietà dell'oggetto, o qualche calcolo arbitrario, o qualsiasi combinazione di questi - tutto utilizzando una procedura , arrayCompare. Magari anche sognare un RegExpcomparatore! So come i bambini adorano quei regexps ...

È il più veloce? No. Ma probabilmente non è nemmeno necessario. Se la velocità fosse l'unica metrica utilizzata per misurare la qualità del nostro codice, un sacco di codice davvero eccezionale verrebbe buttato via - Ecco perché chiamo questo approccio The Practical Way . O forse per essere più equo, un modo pratico. Questa descrizione è adatta a questa risposta perché non sto dicendo che questa risposta sia pratica solo rispetto ad altre risposte; è oggettivamente vero. Abbiamo raggiunto un alto grado di praticità con pochissimo codice di cui è molto facile ragionare. Nessun altro codice può dire che non abbiamo guadagnato questa descrizione.

Questo la rende la soluzione "giusta" per te? Sta a te decidere. E nessun altro può farlo per te; solo tu sai quali sono le tue esigenze. In quasi tutti i casi, apprezzo il codice semplice, pratico e versatile rispetto a un tipo intelligente e veloce. Ciò che apprezzi potrebbe essere diverso, quindi scegli ciò che funziona per te.


modificare

La mia vecchia risposta era più focalizzata sulla scomposizione arrayEqualin piccole procedure. È un esercizio interessante, ma non è il modo migliore (più pratico) per affrontare questo problema. Se sei interessato, puoi vedere questa cronologia delle revisioni.


8
"il miglior tipo di codice non ha nemmeno bisogno di commenti" ... odio dirlo, ma questo codice potrebbe usare più di un commento e / o un nome diverso - "confrontare" è piuttosto vago. Se sto leggendo correttamente, il tuo "confronto" è essenzialmente un curry ricorsivo "ogni". Penso. O è un "alcuni" ricorsivo al curry? Hmm. Ciò richiede più pensiero del necessario. Forse un nome migliore sarebbe "matrici equivalenti", sfruttando la terminologia standard di "relazione di equivalenza". O, ancora più chiaro (per me comunque), "ricorsivamente equivalente".
Don Hatch,

1
@DonHatch grazie per l'opportunità di rispondere. Con "confronta" intendi arrayCompare? Sì, la funzione è curry, ma differisce da somee every. arrayComparerichiede un comparatore e due array per confrontare. Ho scelto un nome specificamente generico perché possiamo confrontare le matrici usando qualsiasi funzione arbitraria. La funzione è curry, quindi può essere specializzata per creare nuove funzioni di confronto di array (ad es arrayEqual.). Puoi suggerire un nome migliore? Quali aree ritieni abbiano bisogno di ulteriori commenti o spiegazioni? Sono felice di discutere ^ _ ^
Grazie

1
Non sono sicuro che il mio punto sia ancora chiaro, ma il mio punto è che la tua funzione non è realmente destinata ad assumere una funzione arbitraria , non credo, è destinata a prendere una relazione di equivalenza e restituisce una relazione di equivalenza. Questo è importante: non farebbe nulla di sensato (non credo) se fosse dato un altro tipo di funzione binaria arbitraria come quelle che ho menzionato, anche quelle che la gente spesso chiama "confronta". Quindi penso che sarebbe utile mettere "equivalente" nel nome al posto di "confronta".
Don Hatch,

1
@ftor, autore: risposta super utile, bel lavoro, +1. Feedback: sostenete la semplicità, ma per molti sviluppatori un'espressione con tre frecce su una riga è semplice o facile da capire. Ad esempio: f => ([x, ... xs]) => ([y, ... ys]) =>. Lo uso costantemente e devo ancora scomporlo mentalmente, piuttosto che "guardarlo". Il secondo punto è giusto, usa ogni. Anche soppesando le tue ragioni, a conti fatti mi sembra migliore non solo per me, ma anche dal tuo punto di vista quando tenti di dedurre la tua filosofia progettuale.
Whitneyland,

1
Capisco che questo è un luogo per l'apprendimento, ma qui presumo che il programmatore medio che studia lo stile funzionale possa trasformare qualsiasi funzione al curry in una non fretta. La mia risposta non suggerisce che questo stile debba essere usato nel tuo programma - scrivilo senza fretta, scrivilo usando le tue regole di rientro, scrivilo come vuoi - Scrivo le mie risposte in uno stile che credo esprima il programma migliore. Mi piace anche invitare altri a sfidare il modo in cui esprimiamo i nostri programmi in modo sintattico
Grazie,

54

Nello spirito della domanda originale:

Vorrei confrontare due array ... idealmente, in modo efficiente . Niente di speciale , solo vero se sono identici e falso in caso contrario.

Ho eseguito test delle prestazioni su alcuni dei suggerimenti più semplici proposti qui con i seguenti risultati (da veloce a lento):

mentre (67%) da Tim Down

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

ogni (69%) dall'utente2782196

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

riduzione (74%) dei DEI

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

join & toString (78%) di Gaizka Allende & vivek

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

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

half toString (90%) di Victor Palomo

a1 == a2.toString();

stringify (100%) di radtek

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

Si noti che gli esempi seguenti presuppongono che gli array siano ordinati, array monodimensionali. .lengthil confronto è stato rimosso per un benchmark comune (aggiungi a1.length === a2.lengtha uno qualsiasi dei suggerimenti e otterrai un aumento delle prestazioni del 10% circa). Scegli le soluzioni più adatte a te conoscendo la velocità e la limitazione di ciascuna.

Nota non correlata: è interessante vedere la gente che ottiene John Waynes con il grilletto sul pulsante di voto in basso su risposte perfettamente legittime a questa domanda.


Il collegamento apre un test vuoto.
Alexander Abakumov,

Se aumenti le dimensioni dell'array, questi numeri non si applicano (in particolare l'approccio di riduzione). Prova con Array.from({length: 1000}).map((a,v)=> $ {v}.padStart(10,2));
Narayon il

funziona solo per array poco profondi
Ramesh Rajendran,

28

Basandomi sulla risposta di Tomáš Zato, concordo sul fatto che solo scorrere le matrici è il più veloce. Inoltre (come altri hanno già affermato), la funzione dovrebbe essere chiamata uguale / uguale, non confronto. Alla luce di ciò, ho modificato la funzione per gestire le matrici di confronto per somiglianza - cioè hanno gli stessi elementi, ma fuori servizio - per uso personale, e ho pensato di metterlo qui perché tutti lo vedessero.

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

Questa funzione accetta un parametro aggiuntivo di rigoroso che per impostazione predefinita è true. Questo rigoroso parametro definisce se gli array devono essere completamente uguali in entrambi i contenuti e nell'ordine di tali contenuti, o semplicemente contenere gli stessi contenuti.

Esempio:

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

Ho anche scritto un rapido jsfiddle con la funzione e questo esempio:
http://jsfiddle.net/Roundaround/DLkxX/


12

Anche se questo ha molte risposte, una che credo possa essere di aiuto:

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

Non è indicato nella domanda come apparirà la struttura dell'array, quindi se sai con certezza che non avrai array nidificati né oggetti nel tuo array (è successo a me, ecco perché sono arrivato a questo risposta) il codice sopra funzionerà.

Quello che succede è che utilizziamo l'operatore spread (...) per concaturare entrambi gli array, quindi usiamo Set per eliminare eventuali duplicati. Una volta che hai che puoi confrontare le loro dimensioni, se tutti e tre gli array hanno le stesse dimensioni sei a posto.

Questa risposta ignora anche l'ordine degli elementi , come ho detto, la situazione esatta mi è successa, quindi forse qualcuno nella stessa situazione potrebbe finire qui (come ho fatto io).


Edit1.

Rispondere alla domanda di Dmitry Grinko: "Perché hai usato l'operatore di diffusione (...) qui - ... nuovo set? Non funziona"

Considera questo codice:

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

Otterrai

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

Per lavorare con quel valore dovresti usare alcune proprietà Set (vedi https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set ). D'altra parte, quando si utilizza questo codice:

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

Otterrai

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

Questa è la differenza, il primo mi darebbe un set, funzionerebbe anche perché potrei ottenere le dimensioni di quel set, ma il secondo mi dà l'array di cui ho bisogno, che è più diretto alla risoluzione.


Perché hai usato l'operatore spread (...) qui - ... nuovo set? Non funziona
Dmitry Grinko,

Dmitry Grinko Credo di aver risposto alla tua domanda sul mio Edit1. Ma non sono sicuro di cosa intendevi dicendo "non funziona", poiché entrambe le risposte possono metterti in mezzo
Jeferson Euclides,

10

Sulle stesse linee di JSON.encode è usare 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

L'unico problema è se ti preoccupi dei tipi che l'ultimo test di confronto. Se ti interessano i tipi, dovrai fare un ciclo.

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

Se l'ordine deve rimanere lo stesso, che è solo un ciclo, non è necessario alcun ordinamento.

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
Funziona solo con determinati array e sarà molto lento con array di grandi dimensioni.
Tomáš Zato - Ripristina Monica il

2
Anche la generazione di JSON è in loop, solo tu (o sembra così) non lo sai. Oltre al looping, la generazione di JSON richiede anche più memoria: crea 2 rappresentazioni di stringhe di detti array prima del confronto. La funzione downwote è implementata per ordinare le risposte dal meglio al peggio. Penso che la tua risposta non sia una buona risposta, quindi l'ho sottovalutata.
Tomáš Zato - Ripristina Monica il

2
Scusa, ho appena detto JSON invece di .join(). Forse se affermassi che la tua seconda soluzione è primaria (in quanto è la migliore, anche se senza denti contro array multidimensionali), non ti giudicherei in questo modo. Finora, ho declassato tutte le risposte che convertono le matrici in stringhe. Inoltre, ho votato a favore di tutto ciò che usa nel modo giusto, nel caso ne avessi bisogno per saperlo. Ciò significa che la risposta di @Tim Down e quella di Bireys.
Tomáš Zato - Ripristina Monica il

6
Prima versione FAILS: checkArrays([1,2,3] , ["1,2",3]) == trueed è molto improbabile che sia quello che vuoi che accada!
Doin,

2
@epascarello: Sì, puoi ma (a parte l'inefficienza del separatore molto lungo che suggerisci) significa che ci saranno casi limite (dove l'array contiene una stringa con il tuo separatore al suo interno) in cui la funzione checkArrays () si comporta male . Questo potrebbe non essere un problema se conosci qualcosa sul contenuto degli array (quindi puoi scegliere un separatore di cui non sarai sicuro negli elementi dell'array), ma se stai provando a scrivere un confronto generale dell'array funzione, quindi l'utilizzo in join()questo modo lo rende leggermente buggy!
Doin,

7

Ecco una versione di 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)
}

Alcuni casi di test per la moka:

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

Se si utilizza un framework di test come Mocha con la libreria di asserzioni Chai , è possibile utilizzare l' uguaglianza profonda per confrontare le matrici.

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

Questo dovrebbe tornare vero solo se le matrici hanno elementi uguali negli indici corrispondenti.


6

Se sono solo due matrici di numeri o stringhe, questa è una veloce di una riga

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

const array3 = [1, 2, 3];
const array4 = [1, 2, 3];
console.log(array3.join(',') === array4.join(',')) //true

const array1 = [1]; const array2 = [1, 1]; console.log (array1.join ('') === array2.join ('')) // restituisce true
Dan M.

non dovrebbe: array1.join ('') è '1' e array2.join ('') è '11'
Gaizka Allende,

scusa, errore di battitura. Il primo array dovrebbe essere [11]. Abbastanza ovvio sul perché questo accada e su come risolvere.
Dan M.,

Non sono sicuro di cosa ti occupi, è piuttosto semplice: [1] .join () è "1" e [1,1] .join () è "1,1", quindi non saranno mai uguali
Gaizka Allende

per favore, leggi di nuovo il mio commento più attentamente. Se ancora non lo vedi, ti preghiamo di fare un bottino su ideone.com/KFu427
Dan M.,

5

Nel mio caso, le matrici confrontate contengono solo numeri e stringhe. Questa funzione ti mostrerà se le matrici contengono gli stessi elementi.

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

Proviamolo!

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

La domanda non ti chiede di ordinare, quindi la tua soluzione è sbagliata per esempi come are_arrs_equal([1,2], [2,1]). Inoltre, vedi altre discussioni in questa pagina per capire perché stringere è inutile, fragile e sbagliato.
Tratta bene le tue mod

are_arrs_equal([1,2], [2,1])ritorna truecome previsto. Forse questa soluzione non è l'ideale, ma ha funzionato per me.
Sì,

Questo è esattamente il problema, quei due non sono uguali in alcun senso sano della parola "uguale" per una struttura di dati ordinata . Sono matrici, non insiemi, e se vuoi impostare l'uguaglianza dovresti chiamarla così - e rispondere a una domanda diversa. :-)
tratta bene le tue mod il

1
Sono d'accordo con i commenti sopra, ma questa soluzione funziona anche per me nei miei semplici array di numeri interi, in cui l'ordine non è importante, quindi lo userò.
Tomazahlin,

1
Non riesce per are_arrs_match([1,2], ["1,2"])(ritorna true). E nota che la the sort()chiamata modificherà le matrici di input - questo potrebbe non essere desiderabile.
Try-catch-finalmente il

5

Questo confronta 2 matrici non ordinate:

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

Sebbene costosa (in termini di risorse di calcolo), questa è una soluzione robusta che dovrebbe essere buona per vari tipi e non si basa sull'ordinamento!
user3.1415927


4

Potremmo farlo in modo funzionale, usando 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

Il codice non gestirà il caso in modo appropriato quando entrambi gli array hanno gli stessi elementi ma non nello stesso ordine.

Dai un'occhiata al mio codice con il tuo esempio che confronta due matrici i cui elementi sono numeri, potresti modificarlo o estenderlo per altri tipi di elementi (utilizzando .join () anziché .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

Herer è la mia soluzione:

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

Funziona con qualsiasi struttura di dati nidificata e ovviamente ignora i metodi degli oggetti. Non pensare nemmeno di estendere Object.prototype con questo metodo, quando l'ho provato una volta, jQuery si è rotto;)

Per la maggior parte degli array è ancora più veloce della maggior parte delle soluzioni di serializzazione. È probabilmente il metodo di confronto più veloce per le matrici di record di oggetti.


non buono! questi danno vero: equal({}, {a:1})e equal({}, null)questi errori escono:equal({a:2}, null)
kristianlm,

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

È così che l'ho fatto.


Buona soluzione - ma mi chiedo in certe situazioni se non funzionerà sempre come previsto, come con determinati primitivi o array profondamente annidati? Spero che funzioni in ogni circostanza
Ben Rondeau il

3

Confronto di 2 array:

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

funzione chiamante

var isBool = compare(arr1.sort().join(),arr2.sort().join());

Questa risposta non funzionerà, poiché === non si comporta come previsto per gli array.
Michael Yang,

La risposta funziona, anche se === non ha alcun significato qui (poiché sort () funziona solo su array). Anche == funzionerà anche.
Amay Kulkarni,

Provalo tu stesso; viene stampato falso se si esegue questo codice. Ciò è dovuto al confronto dei valori di riferimento degli array con entrambi == e === anziché i loro valori effettivi. == e === sono intesi solo per il confronto di tipi primitivi.
Michael Yang,

Ritorna vero, l'abbiamo usato, ma ho rimosso '===' ora perché non è necessario
Amay Kulkarni

Ah, non ho notato che stavi convertendo in una stringa e chiamando la funzione dopo l'ordinamento e l'unione; le mie scuse.
Michael Yang,

3

Credo nel semplice JSe con ECMAScript 2015, che è dolce e semplice da capire.

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

}

spero che possa aiutare qualcuno.


1
Perché è necessario il controllo viceversa? Sappiamo che le matrici hanno le stesse dimensioni, quindi se ogni elemento in array1 si trova anche in array2; perché dovremmo quindi verificare che ogni elemento in array2 sia anche in array1?
JeffryHouser,

2

Estensione dell'idea di Tomáš Zato. Array.prototype.compare di Tomas dovrebbe essere infatti chiamato Array.prototype.compareIdentical.

Passa:

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

Ma fallisce su:

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

Ecco la versione migliore (secondo me):

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. Se "fallisce" nell'esempio che hai dato, allora è solo il caso di una definizione in qualche modo arbitraria di "fallito". Perché dovresti aspettarti che quei due diversi array siano considerati uguali? Non hai nemmeno spiegato quale concetto di "uguaglianza" stai cercando di implementare qui, o perché è ragionevole o utile, ma sembra che tu voglia confrontare le matrici multidimensionali come se fossero collassate in monodimensionali quelli. Se è così, non l'hai nemmeno ottenuto: [1,2] .compare ([[1,2]]) dà false con la tua versione, proprio come con Tomáš.
Mark Amery,

Sulla base di ciò che potrei dedurre, sta dicendo che [1, 2, 3, 4] e [1, 3, 2, 4] dovrebbero essere confrontati alla pari (l'ordine non ha importanza).
Gautham Badhrinathan,

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

////// O ///////

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)

Puoi anche tu qualche funzione che non ripeterà completamente se otteniamo soddisfatte le condizioni richieste, come sopra
Vasanth

2

Un altro approccio con pochissimo codice (utilizzando Array ridurre e Array include ):

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

Se vuoi confrontare anche l'uguaglianza dell'ordine:

arr1.length == arr2.length && arr1.reduce((a, b, i) => a && arr2[i], true)
  • Il lengthcontrollo assicura che l'insieme di elementi in un array non sia solo un sottoinsieme dell'altro.

  • Il riduttore viene utilizzato per attraversare un array e cercare ciascun elemento in un altro array. Se non viene trovato un elemento, viene restituita la funzione di riduzione false.

    1. Nel primo esempio è stato testato che un elemento è incluso
    2. Il secondo esempio controlla anche l'ordine

1
potresti spiegare un po 'il tuo codice per rendere più chiara questa risposta?
Ted

1. confronta le lunghezze degli array per assicurarti che un array non sia un sottoinsieme dell'altro
DEls

2. utilizzare il riduttore per scorrere un array e cercare ciascun elemento nell'altro array. Se non viene trovato un elemento, la funzione di riduzione restituisce 'false'
DEls

@DEls: modificato la tua spiegazione nella risposta (leggermente riformulata ed estesa). Ora puoi rimuovere i tuoi commenti e contrassegnare il primo commento e questo come obsoleto.
Try-catch-finalmente il

2

Un approccio semplice:

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

Già alcune grandi risposte, ma vorrei condividere un'altra idea che si è dimostrata affidabile nel confronto tra array. Possiamo confrontare due array usando JSON.stringify () . Creerà una stringa dall'array e quindi confronterà due stringhe ottenute da due array per l'uguaglianza

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

Ricorsivo e funziona su array 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

Funziona con MULTIPLE argomenti con NESTED array:

//: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  
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.