Verwenden von lodash zum Vergleichen von Arrays (Elemente existieren ohne Reihenfolge)


124

Ich weiß, dass ich es mit Schleifen machen kann, aber ich versuche einen eleganten Weg zu finden, dies zu tun:

Ich habe zwei Arrays:

var array1 = [['a', 'b'], ['b', 'c']];
var array2 = [['b', 'c'], ['a', 'b']];

Ich möchte damit lodashbestätigen, dass die beiden oben genannten Arrays identisch sind. Mit "das Gleiche" meine ich, dass es keinen Gegenstand array1gibt, der nicht in enthalten ist array2.

In Bezug auf die Überprüfung der Gleichheit zwischen diesen Elementen:

['a', 'b'] == ['b', 'a'] 

oder

['a', 'b'] == ['a', 'b'] 

Beide funktionieren, da die Buchstaben immer in Ordnung sind.

Antworten:


223

Wenn Sie das äußere Array sortieren, können Sie es verwenden, _.isEqual()da das innere Array bereits sortiert ist.

var array1 = [['a', 'b'], ['b', 'c']];
var array2 = [['b', 'c'], ['a', 'b']];
_.isEqual(array1.sort(), array2.sort()); //true

Beachten Sie, dass .sort()die Arrays mutiert werden. Wenn dies ein Problem für Sie ist, erstellen Sie zuerst eine Kopie mit (zum Beispiel) .slice()oder dem Spread-Operator ( ...).

Oder tun Sie, was Daniel Budick in einem Kommentar unten empfiehlt:

_.isEqual(_.sortBy(array1), _.sortBy(array2))

Lodashs sortBy()mutieren das Array nicht.


6
Berücksichtigen Sie, dass array.sort () das ursprüngliche Array mutiert. Vielleicht ist dieser besser: var array1 = [['a', 'b'], ['b', 'c']]; var array2 = [['b', 'c'], ['a', 'b']]; _.isEqual ([... array1] .sort (), [... array2] .sort ()); // wahr
Yaniv Efraim

3
Es wurden zwei Sätze hinzugefügt, die darauf .sort()hinweisen , dass sie mutieren, und Optionen zum Kopieren zuerst vorgeschlagen, wenn dies ein Problem für den Benutzer ist.
Trott

6
Wenn Sie bereits lodash verwenden, können Sie dies tun _.isEqual(_.sortBy(array1), _sortBy(array2)), um eine Mutation zu verhindern.
Daniel Budick

1
@ DanielBudick Danke! Ich habe das der Antwort hinzugefügt. Toller Vorschlag.
Trott

31

Sie können lodashs verwenden xorfür diese

doArraysContainSameElements = _.xor(arr1, arr2).length === 0

Wenn Sie Array [1, 1] als anders als Array [1] betrachten, können Sie die Leistung ein wenig verbessern:

doArraysContainSameElements = arr1.length === arr2.length === 0 && _.xor(arr1, arr2).length === 0

1
Arrays müssen sowieso sortiert werden.
Sovattha Sok

1
Dies sollte der bessere Weg für eine neuere Version sein
Leonardo

@Sovattha Sok Die Arrays müssen nicht sortiert werden. Wenn _.xor([3,4], [4,3]).length == 0du es tust, wirst du wahr.
Nikolay

1
Ein Wort der Vorsicht: Diese Technik funktioniert gut für "kleine" Arrays, aber es kann eine Schmerzleistung und eine Speicherleistung sein, wenn Ihre Arrays riesig sind und sich größtenteils unterscheiden, da _.xor () den ersten Unterschied überwinden wird. Mit anderen Worten, es kehrt beim ersten erkannten Unterschied nicht schnell zurück.
XDS

6

Mit "dasselbe" meine ich, dass es in Array1 kein Element gibt, das nicht in Array2 enthalten ist.

Sie könnten () und Differenz () für diesen Einsatz Flatten, die gut funktioniert , wenn Sie es egal, ob es Elemente in array2die nicht sind in array1. Es hört sich so an, als würden Sie fragen, ob Array1 eine Teilmenge von Array2 ist .

var array1 = [['a', 'b'], ['b', 'c']];
var array2 = [['b', 'c'], ['a', 'b']];

function isSubset(source, target) {
    return !_.difference(_.flatten(source), _.flatten(target)).length;
}

isSubset(array1, array2); // → true
array1.push('d');
isSubset(array1, array2); // → false
isSubset(array2, array1); // → true

3

Hier gibt es bereits Antworten, aber hier ist meine reine JS-Implementierung. Ich bin mir nicht sicher, ob es optimal ist, aber es ist sicher transparent, lesbar und einfach.

// Does array a contain elements of array b?
const contains = (a, b) => new Set([...a, ...b]).size === a.length
const isEqualSet = (a, b) => contains(a, b) && contains(b, a)

Das Grundprinzip in contains()ist, dass, wenn aalle Elemente von enthalten sind b, das Einfügen in dieselbe Menge die Größe nicht ändern würde.

Zum Beispiel, wenn const a = [1,2,3,4]und const b = [1,2]dann new Set([...a, ...b]) === {1,2,3,4}. Wie Sie sehen können, enthält die resultierende Menge dieselben Elemente wie a.

Um es übersichtlicher zu gestalten, können wir es von dort aus auf Folgendes reduzieren:

const isEqualSet = (a, b) => {
  const unionSize = new Set([...a, ...b])
  return unionSize === a.length && unionSize === b.length
}

1

PURE JS (funktioniert auch, wenn Arrays und Subarrays mehr als 2 Elemente mit beliebiger Reihenfolge haben). Wenn Zeichenfolgen die ,Verwendung als join('-')Parameterzeichen enthalten (kann utf sein), das in Zeichenfolgen nicht verwendet wird

array1.map(x=>x.sort()).sort().join() === array2.map(x=>x.sort()).sort().join()


0

Wir können die _.differenceFunktion verwenden, um festzustellen, ob es einen Unterschied gibt oder nicht.

function isSame(arrayOne, arrayTwo) {
   var a = _.unique(arrayOne),
       b = _.unique(arrayTwo);

   if (a.length <= b.length) {
      a = arrayTwo;
      b = arrayOne;
      return _.isEmpty(_.difference(a.sort(), b.sort()));
   } else {
      return false;
   }

}

// examples
console.log(isSame([1, 2, 3], [1, 2, 3])); // true
console.log(isSame([1, 2, 4], [1, 2, 3])); // false
console.log(isSame([1, 2], [2, 3, 1])); // false
console.log(isSame([2, 3, 1], [1, 2])); // false

// Test cases pointed by Mariano Desanze, Thanks.
console.log(isSame([1, 2, 3], [1, 2, 2])); // false
console.log(isSame([1, 2, 2], [1, 2, 2])); // true
console.log(isSame([1, 2, 2], [1, 2, 3])); // false

Ich hoffe, dies wird dir helfen.


5
Falsch, Ihre Funktion wird truefürconsole.log(isSame([1,2], [2,3,1]));
David Lin

3
Vielen Dank an @DavidLin, um darauf hinzuweisen. Ich habe die Änderungen vorgenommen, um diesen Fall zu berücksichtigen. Vielen Dank und Entschuldigung für die Unannehmlichkeiten.
Amitesh

2
Sie müssen nicht die Plätze für a & b wechseln, wenn die Längen nicht gleich sind. Wenn sich die Längen unterscheiden, können sie nicht bereits gleich sein. Wenn also (arrayOne.lenght! == arrayTwo.lenght) false zurückgibt;
Alex

1
-1 Es macht keinen Sinn, diese aund bVariablen zu haben. Sie verwenden nur diese Variablen innerhalb des if-thenTeils, und als erstes verwerfen Sie die in Zeile 2 geladenen Werte. Ich denke, die folgende einzelne Zeile funktioniert genauso : return arrayOne.length <= arrayTwo.length && _.isEmpty(_.difference(arrayTwo.sort(), arrayTwo.sort());. Und das <=kann auch verbessert werden ===.
Mariano Desanze

1
Und _.differencegibt fehlende Elemente des 1. Arguments zurück, aber keine fehlenden Elemente des 2. Arguments. Dies wird also fälschlicherweise zurückgegeben, truewenn Sie Elemente am 1. in 2. wiederholen : isSame([1, 2, 3], [1, 2, 2]).
Mariano Desanze

0

Bearbeiten: Ich habe den mehrdimensionalen Aspekt dieser Frage übersehen, daher lasse ich dies hier, falls es den Leuten hilft, eindimensionale Arrays zu vergleichen

Es ist eine alte Frage, aber ich hatte Probleme mit der Geschwindigkeit der Verwendung von .sort()oder sortBy(), also habe ich diese stattdessen verwendet:

function arraysContainSameStrings(array1: string[], array2: string[]): boolean {
  return (
    array1.length === array2.length &&
    array1.every((str) => array2.includes(str)) &&
    array2.every((str) => array1.includes(str))
  )
}

Es sollte schnell scheitern und funktioniert für meine Zwecke einwandfrei.


Ist die letzte Überprüfung wirklich notwendig? array1.every((str) => array2.includes(str))sollte genug sein. Auch das OP wollte lodash verwenden, sollten Sie zumindest sagen, warum Sie eine VanillaJS-Lösung vorschlagen (... jetzt, wo wir alle haben und einschließen ...). Bitte geben Sie auch ein Beispiel an, wie Sie Ihre Funktion auf das bereitgestellte Problem anwenden können (zweidimensionale Arrays).
Line-o

Das ist ein guter Punkt - ich habe nicht auf den mehrdimensionalen Aspekt eingegangen, nicht auf das Erfordernis von Lodash. Ich dachte, es wäre nützlich, wenn jemand (wie ich) lodash methods to compare arrays without considering ordernach einer Alternative im modernen Javascript sucht . Die zweite Prüfung ist erforderlich, da arraysContainSameStrings(['1', '2', '2'], ['1', '2', '3'])sonst true zurückgegeben würde. Ich werde es hier lassen, da es vielleicht hilft, aber ich schätze, dass ich die Frage nicht beantwortet habe
charliematters
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.