Hoe arrays in JavaScript te vergelijken?

Ik zou graag twee arrays willen vergelijken … idealiter, efficiënt. Niets bijzonders, gewoon trueals ze identiek zijn, en falsezo niet. Niet verrassend, de vergelijkingsoperator lijkt niet te werken.

var a1 = [1,2,3];
var a2 = [1,2,3];
console.log(a1==a2);    // Returns false
console.log(JSON.stringify(a1)==JSON.stringify(a2));    // Returns true

JSON die codeert voor elke array doet, maar is er een snellere of “betere” manier om simpelweg overeenstemming te vergelijken zonder te hoevenen door elke waarde?


1, Autoriteit 100%

Om overeenstemming te vergelijken, loop ze door hen heen en vergelijk elke waarde:

Arrays vergelijken:

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

Gebruik:

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

Je zou kunnen zeggen “Maar het is veel sneller om strings te vergelijken – geen lussen…” wel, dan moet je er rekening mee houden dat er lussen ZIJN. Eerste recursieve lus die Array converteert naar string en tweede, die twee strings vergelijkt. Deze methode is dus sneller dan het gebruik van string.

Ik ben van mening dat grotere hoeveelheden gegevens altijd in arrays moeten worden opgeslagen, niet in objecten. Als u echter objecten gebruikt, kunnen ze ook gedeeltelijk worden vergeleken.
Zo gaat het:

Objecten vergelijken:

Ik heb hierboven aangegeven dat twee object instantiesnooit gelijk zullen zijn, zelfs als ze op dit moment dezelfde gegevens bevatten:

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

Dit heeft een reden, aangezien er bijvoorbeeld privévariabelen binnen objecten kunnen zijn.

Als u echter alleen de objectstructuur gebruikt om gegevens te bevatten, is vergelijken nog steeds mogelijk:

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

Onthoud echter dat deze is bedoeld om JSON-achtige gegevens te vergelijken, niet klasse-instanties en andere dingen. Als je meer gecompliceerde objecten wilt vergelijken, kijk dan naar dit antwoord en de superlange functie.
Om dit te laten werken met Array.equalsmoet je de originele functie een beetje aanpassen:

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

Ik heb een kleine testtool gemaakt voor beide functies.

Bonus: geneste arrays met indexOfen contains

Samy Bencherif heeftnuttige functies voor het geval u zoekt naar een specifiek object in geneste arrays, die hier beschikbaar zijn: https://jsfiddle .net/SamyBencherif/8352y6yw/


Antwoord 2, autoriteit 51%

Hoewel dit alleen werkt voor scalaire arrays (zie opmerking hieronder), is het kort:

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

Rr, in ECMAScript 6 / CoffeeScript / TypeScript met pijlfuncties:

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

(Opmerking: ‘scalar’ betekent hier waarden die direct kunnen worden vergeleken met behulp van ===. Dus: getallen, strings, objecten door verwijzing, functies door verwijzing. Zie de MDN-referentievoor meer informatie over de vergelijkingsoperators).

UPDATE

Van wat ik uit de opmerkingen heb gelezen, kan het sorteren van de array en het vergelijken een nauwkeurig resultaat opleveren:

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

Bijvoorbeeld:

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

Dan zou de bovenstaande code true

geven


3, Autoriteit 26%

Ik hou ervan om de undercore-bibliotheek te gebruiken voor array / object Heavy Codering Projecten … in Undercore en Lodash, ongeacht of u reeksen of objecten vergelijkt, ziet het er gewoon als volgt uit:

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

4, Autoriteit 10%

In de geest van de oorspronkelijke vraag:

Ik zou graag twee arrays willen vergelijken … idealiter efficiënt . niets
Fancy
, gewoon waar als ze identiek zijn en onwaar, zo niet.

Ik heb prestatietests uitgevoerd op enkele van de meer eenvoudige suggesties die hier zijn voorgesteld met de volgende resultaten ( snel om te vertragen):

terwijl (67%) door Tim Down

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

elke (69%) door user2782196

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

verlaag (74%) door Deis

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

Word lid & amp; TOSTRING (78%) door Gaizka Allende & Amp; vivek

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

Half Tostring (90%) door Victor Palomo

a1 == a2.toString();

stringify (100%) door Radtek

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

Opmerkingde onderstaande voorbeelden gaan ervan uit dat de arrays gesorteerde, eendimensionale arrays zijn. .lengthvergelijking is verwijderd voor een gemeenschappelijke benchmark (voeg a1.length === a2.lengthtoe aan een van de suggesties en je krijgt een prestatieverbetering van ~10% ). Kies de oplossingen die voor u het beste werken, wetende wat de snelheid en beperking van elke oplossing is.

Niet-gerelateerde opmerking:het is interessant om te zien dat mensen alle schietgrage John Waynes op de neerstemknop krijgen op volkomen legitieme antwoorden op deze vraag.


Antwoord 5, autoriteit 8%

De praktische manier

Ik denk dat het verkeerd is om te zeggen dat een bepaalde implementatie “The Right Way™” is als het alleen maar “goed” (“juist”) is in tegenstelling tot een “foute” oplossing. De oplossing van Tomáš is een duidelijke verbetering ten opzichte van string-gebaseerde array-vergelijking, maar dat betekent niet dat het objectief “juist” is. Wat is goedeigenlijk? Is het de snelste? Is het het meest flexibel? Is het het gemakkelijkst te begrijpen? Is het de snelste om te debuggen? Gebruikt het de minste bewerkingen? Heeft het bijwerkingen? Geen enkele oplossing kan het beste van alle dingen hebben.

Tomáš zou kunnen zeggen dat zijn oplossing snel is, maar ik zou ook zeggen dat het onnodig ingewikkeld is. Het probeert een alles-in-één oplossing te zijn die werkt voor alle arrays, genest of niet. Het accepteert zelfs meer dan alleen arrays als invoer en probeert nog steeds een “geldig” antwoord te geven.


Algemene middelen bieden herbruikbaarheid

Mijn antwoord zal het probleem anders benaderen. Ik zal beginnen met een generieke arrayCompare-procedure die zich alleen bezighoudt met het doorlopen van de arrays. Van daaruit bouwen we onze andere basisvergelijkingsfuncties zoals arrayEqualen arrayDeepEqual, enz.

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

Naar mijn mening heeft de beste soort code zelfs geen commentaar nodig, en dit is geen uitzondering. Er gebeurt hier zo weinig dat u het gedrag van deze procedure bijna zonder enige moeite kunt begrijpen. Natuurlijk, een deel van de ES6-syntaxis lijkt je nu misschien vreemd, maar dat is alleen omdat ES6 relatief nieuw is.

Zoals het type suggereert, neemt arrayComparede vergelijkingsfunctie fen twee invoerarrays, xsen ys. Voor het grootste deel hoeven we alleen maar f (x) (y)aan te roepen voor elk element in de invoerarrays. We retourneren een vroege falseals de door de gebruiker gedefinieerde ffalseretourneert – dankzij de &&‘s evaluatie van kortsluiting. Dus ja, dit betekent dat de comparator de iteratie vroegtijdig kan stoppen en het doorlussen van de rest van de invoerarray kan voorkomen als dat niet nodig is.


Strikte vergelijking

Vervolgens kunnen we met behulp van onze arrayCompare-functie gemakkelijk andere functies maken die we mogelijk nodig hebben. We beginnen met de elementaire 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

Zo simpel is het. arrayEqualkan worden gedefinieerd met arrayCompareen een comparatorfunctie die avergelijkt met bmet behulp van ===(voor strikte gelijkheid).

Merk op dat we equalook definiëren als zijn eigen functie. Dit benadrukt de rol van arrayCompareals een functie van hogere orde om onze eerste-orde-vergelijker te gebruiken in de context van een ander gegevenstype (Array).


Losse vergelijking

We zouden net zo gemakkelijk arrayLooseEqualkunnen definiëren door in plaats daarvan een ==te gebruiken. Als u nu 1(nummer) vergelijkt met '1'(tekenreeks), is het resultaat 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

Diepe vergelijking (recursief)

Je hebt waarschijnlijk gemerkt dat dit slechts een oppervlakkige vergelijking is. De oplossing van Tomáš is toch zeker “The Right Way™” omdat het een diepgaande vergelijking impliceert, toch?

Nou, onze arrayCompare-procedure is veelzijdig genoeg om te gebruiken op een manier die een diepgaande gelijkheidstest een fluitje van een cent maakt …

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

Zo simpel is het. We bouwen een diepe comparator met behulp van een anderefunctie van hogere orde. Deze keer verpakken we arrayComparemet een aangepaste comparator die controleert of aen barrays zijn. Als dit het geval is, past u arrayDeepCompareopnieuw toe, anders vergelijkt u aen bmet de door de gebruiker opgegeven comparator (f). Dit stelt ons in staat om het diepe vergelijkingsgedrag gescheiden te houden van hoe we de afzonderlijke elementen daadwerkelijk vergelijken. Dat wil zeggen, zoals het bovenstaande voorbeeld laat zien, kunnen we diep vergelijken met behulp van equal, looseEqualof een andere comparator die we maken.

Omdat arrayDeepComparegecurryd is, kunnen we het ook gedeeltelijk toepassen zoals in de vorige voorbeelden

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

Voor mij is dit al een duidelijke verbetering ten opzichte van de oplossing van Tomáš, omdat ik explicieteen oppervlakkige of diepe vergelijking voor mijn arrays kan kiezen, indien nodig.


Objectvergelijking (voorbeeld)

Wat als je een array van objecten hebt of zoiets? Misschien wilt u die arrays als “gelijk” beschouwen als elk object dezelfde id-waarde heeft …

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

Zo simpel is het. Hier heb ik vanilla JS-objecten gebruikt, maar dit type comparator zou kunnen werken voor elkobjecttype; zelfs uw aangepaste objecten. De oplossing van Tomáš zou volledig moeten worden herwerkt om dit soort gelijkheidstests te ondersteunen

Diepe array met objecten? Geen probleem. We hebben zeer veelzijdige, generieke functies gebouwd, zodat ze in een groot aantal verschillende gebruikssituaties werken.

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

Willekeurige vergelijking (voorbeeld)

Of wat als u een ander soort volledig willekeurige vergelijking zou willen maken? Misschien wil ik weten of elke xgroter is dan elke 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

Minder is meer

Je kunt zien dat we meer doen met minder code. Er is niets ingewikkelds aan arrayComparezelf en elk van de aangepaste vergelijkers die we hebben gemaakt, heeft een zeer eenvoudige implementatie.

Met gemak kunnen we precies definiëren hoe we willen dat twee arrays worden vergeleken – ondiep, diep, strikt, los, een objecteigenschap of een willekeurige berekening, of een combinatie hiervan – allemaal met behulp van één procedure , arrayCompare. Misschien zelfs een RegExpcomparator bedenken! Ik weet hoe kinderen dol zijn op die regexp’s …

Is het de snelste? Nee. Maar dat hoeft waarschijnlijk ook niet. Als snelheid de enige maatstaf is die wordt gebruikt om de kwaliteit van onze code te meten, zou veel echt geweldige code worden weggegooid — daarom noem ik deze benadering The Practical Way. Of misschien om eerlijker te zijn, EenPraktische Manier. Deze beschrijving is geschikt voor dit antwoord, omdat ik niet zeg dat dit antwoord alleen praktisch is in vergelijking met een ander antwoord; het is objectief waar. We hebben een hoge mate van bruikbaarheid bereikt met heel weinig code waar heel gemakkelijk over te redeneren is. Geen enkele andere code kan zeggen dat we deze beschrijving niet hebben verdiend.

Maakt dat het de “juiste” oplossing voor u? Dat is klaar voor u om te beslissen. En niemand anders kan dat voor u doen; alleen jij weet wat je behoeften zijn. In bijna alle gevallen waardeerde ik rechtlijnige, praktische en veelzijdige code over slimme en snelle soort. Wat u waardeert, kan verschillen, dus kies wat voor u werkt.


Bewerken

Mijn oude antwoord was meer gericht op het ontbinden arrayEqualin kleine procedures. Het is een interessante oefening, maar niet echt de beste (meest praktische) manier om dit probleem te benaderen. Als u geïnteresseerd bent, kunt u deze revisiegeschiedenis zien.


6, Autoriteit 6%

Het is onduidelijk wat je bedoelt met “identiek”. Zijn bijvoorbeeld de arrays aen bhieronder identiek (let op de geneste arrays)?

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

Hier is een geoptimaliseerde arrayvergelijkingsfunctie die de overeenkomstige elementen van elke array op zijn beurt met behulp van strikte gelijkheid vergelijkt en geen recursieve vergelijking is van arrayelementen die zelf arrays zijn, wat betekent dat voor het bovenstaande voorbeeld, arraysIdentical(a, b)zou terugkeren false. Het werkt in het algemene geval, welke JSON- en join()-Based Solutions niet:

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

7, Autoriteit 3%

Bouw het antwoord van Tomáš Zato, ik ben het ermee eens dat het gewoon door de arrays de snelste is. Bovendien (zoals anderen hebben al vermeld), moet de functie gelijken / gelijk worden genoemd, niet te vergelijken. In het licht hiervan heb ik de functie gewijzigd om de reeksen voor gelijkenis te veroveren – d.w.z. ze hebben dezelfde elementen, maar niet in orde – voor persoonlijk gebruik, en dachten dat ik het hier voor iedereen zou gooien.

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

Deze functie heeft een aanvullende parameter van strikte die standaard naar True is. Deze strikte parameter definieert als de arrays volledig gelijk moeten zijn in zowel de inhoud als de volgorde van die inhoud, of gewoon gewoon dezelfde inhoud bevatten.

Voorbeeld:

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

Ik heb ook een snelle jsfiddle geschreven met de functie en dit voorbeeld:
http://jsfiddle.net/Roundaround/DLkxX/


Antwoord 8

Ook al heeft dit veel antwoorden, een waarvan ik denk dat ze helpen:

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

Het wordt niet vermeld in de vraag hoe de structuur van de array eruit gaat zien, dus als je zeker weet dat je geen geneste arrays of objectenin je array hebt (het is mij overkomen, daarom kwam ik tot dit antwoord) de bovenstaande code zal werken.

Wat er gebeurt, is dat we de spread-operator ( … ) gebruiken om beide arrays samen te voegen, en vervolgens Set gebruiken om duplicaten te elimineren. Als je dat eenmaal hebt, kun je hun maten vergelijken, als alle drie de arrays dezelfde grootte hebben, ben je klaar om te gaan.

Dit antwoord neegt ook de volgorde van de elementen, zoals ik al zei, de exacte situatie is mij overkomen, dus misschien kan iemand in dezelfde situatie hier terechtkomen (zoals ik deed).


Bewerken1.

Beantwoorden van de vraag van Dmitry Grinko: “Waarom heb je hier de spread-operator ( … ) gebruikt – …nieuwe set? Het werkt niet”

Denk aan deze code:

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

Je krijgt

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

Om met die waarde te werken, moet u enkele Set-eigenschappen gebruiken (zie https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set).
Aan de andere kant, wanneer u deze code gebruikt:

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

Je krijgt

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

Dat is het verschil, de eerste zou me een set geven, het zou ook werken omdat ik de grootte van die set zou kunnen krijgen, maar de laatste geeft me de array die ik nodig heb, wat directer is voor de resolutie.


Antwoord 9

Op dezelfde regels als JSON.encode is om join() te gebruiken.

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

Het enige probleem is als je om typen geeft die door de laatste vergelijking worden getest.
Als je om typen geeft, zul je moeten herhalen.

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

Als de bestelling hetzelfde moet blijven, dan is het slechts een lus, er is geen soort nodig.

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

10

In mijn geval vergeleken arrays bevatten alleen cijfers en snaren. Deze functie laat u zien of arrays dezelfde elementen bevatten.

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

Laten we het testen!

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

11

kortste

Probeer een scala aan cijfers:

a1==''+a2

12

Hier is een typert-versie:

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

Sommige testcases voor Mocha:

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

Antwoord 13

Uw code zal de casus niet correct afhandelen wanneer beide arrays dezelfde elementen hebben, maar niet in dezelfde volgorde.

Bekijk mijn code met uw voorbeeld waarin twee arrays worden vergeleken waarvan de elementen getallen zijn, u kunt deze wijzigen of uitbreiden voor andere elementtypen (door .join() te gebruiken in plaats van .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);

Antwoord 14

Je kunt eenvoudig isEqualuit de lodash-bibliotheek gebruiken. Het is zeer efficiënt en schoon.

import {isEqual} from "lodash";
const isTwoArraysEqual = isEqual(array1, array2);

Antwoord 15

Code golfen

Er zijn tal van antwoorden die laten zien hoe u arrays efficiënt kunt vergelijken.

Hieronder is de kortstemanier om twee string- of int-arrays te vergelijken, gemeten in bytes aan code.

const a = [1, 2, 3]
const b = [1, 2, 3]
console.log("1. ", a.join() === b.join())
console.log("2. ", a.join() === [].join())
console.log("3. ", 1 + a === 1 + b)
console.log("4. ", 1 + [] === 1 + b)

Antwoord 16

Als je een testframework gebruikt zoals Mokkamet de Chai-beweringbibliotheek, u kunt diepgebruiken gelijkheid om arrays te vergelijken.

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

Dit zou alleen true moeten retourneren als de arrays gelijke elementen hebben op overeenkomstige indices.


Antwoord 17

Als het slechts twee reeksen getallen of tekenreeksen zijn, is dit een snelle éénregel

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

Antwoord 18

Er is een Fase 1-voorstel, geïntroduceerd in 2020, om de gemakkelijke vergelijking van arrays door Array.prototype.equalstoe te voegen aan de taal. Dit is hoe het zou werken, zonder bibliotheken, monkeypatching of enige andere code:

[1, 2, 3].equals([1, 2, 3]) // evaluates to true
[1, 2, undefined].equals([1, 2, 3]) // evaluates to false
[1, [2, [3, 4]]].equals([1, [2, [3, 4]]]) // evaluates to true

Het is slechts een voorstel tot nu toe – TC39 zal nu “tijd besteden aan het onderzoeken van de probleemruimte , Oplossingen en Cross-Snijproblemen “. Als het tot fase 2 maakt, heeft het een goede kans om uiteindelijk in de juiste taal te worden geïntegreerd.


19

Dit vergelijkt 2 ongesorteerde arrays:

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

20

We kunnen dit de functionele manier doen, met behulp van every(https://developer.mozilla.org/en/docs/web/javascript/referentie/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

21

Hier een mogelijkheid voor ongesorteerde arrays en aangepaste vergelijking:

   const array1 = [1,3,2,4,5];
    const array2 = [1,3,2,4,5];
    const isInArray1 = array1.every(item => array2.find(item2 => item===item2))
    const isInArray2 = array2.every(item => array1.find(item2 => item===item2))
    const isSameArray = array1.length === array2.length && isInArray1 && isInArray2
    console.log(isSameArray); //true

22

Herer’s mijn oplossing:

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

Werkt met elke geneste data-structuur en negeert duidelijk de methoden van objecten. Denk niet eens aan het uitbreiden van Object.Prototype met deze methode, toen ik dit eenmaal probeerde, heeft JQuery gebroken;)

Voor de meeste arrays is het nog steeds sneller dan de meeste serialisatie-oplossingen. Het is waarschijnlijk de snelste vergelijkingsmethode voor arrays van objectrecords.


23

Nog een benadering met heel weinig code (met Array Verminder en array bevat ):

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

Als u ook de gelijkheid van de bestelling wilt vergelijken:

arr1.length == arr2.length && arr1.reduce((a, b, i) => a && arr2[i], true)
  • De lengthControleren zorgt ervoor dat de set elementen in één array niet alleen een subset van de andere is.

  • De reducer wordt gebruikt om door één array te lopen en naar elk item in een andere array te zoeken. Als een item niet wordt gevonden, retourneert de vermindering de functie false.

    1. In het eerste voorbeeld wordt getest dat een element is opgenomen
    2. De tweede voorbeeldcontrole voor de bestelling ook

24

Een eenvoudige aanpak:

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

25

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

Zo heb ik het gedaan.


Antwoord 26

2 arrays vergelijken:

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

aanroepfunctie

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

Antwoord 27

Al een aantal geweldige antwoorden. Maar ik wil graag een ander idee delen dat betrouwbaar is gebleken bij het vergelijken van arrays. We kunnen twee arrays vergelijken met behulp van JSON .stringify ( ). Het maakt een string uit de array en vergelijkt dus twee verkregen strings van twee arrays voor gelijkheid

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

Antwoord 28

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  

Antwoord 29

Een alternatieve manier om filter- en pijlfuncties te gebruiken

arrOne.length === arrTwo.length && arrOne.filter((currVal, idx) => currVal !== arrTwo[idx]).length === 0

Other episodes