Wie berechnet man den Schnittpunkt mehrerer Arrays in JavaScript? Und was tut [equals: function] bedeuten?
Lesezeit: 8 Minuten
Ich bin mir dieser Frage bewusst, dem einfachsten Code für die Schnittmenge von Arrays, aber alle Lösungen gehen davon aus, dass die Anzahl der Arrays zwei ist, was in meinem Fall nicht sicher sein kann.
Ich habe Divs auf einer Seite mit Daten, die Arrays enthalten. Ich möchte die Werte finden, die allen Arrays gemeinsam sind. Ich weiß nicht, wie viele Divs/Arrays ich im Voraus haben werde. Was ist der beste Weg, um Werte zu berechnen, die allen Arrays gemeinsam sind?
var array1 = ["Lorem", "ipsum", "dolor"];
var array2 = ["Lorem", "ipsum", "quick", "brown", "foo"];
var array3 = ["Jumps", "Over", "Lazy", "Lorem"];
var array4 = [1337, 420, 666, "Lorem"];
//Result should be ["Lorem"];
Ich habe an anderer Stelle eine andere Lösung mit Underscore.js gefunden.
var arrayOfArrays = [[4234, 2323, 43], [1323, 43, 1313], [23, 34, 43]];
_.intersection.apply(_, arrayOfArrays)
//Result is [43]
Ich habe dies mit einfachen Dummy-Daten an meinem Ende getestet und es scheint zu funktionieren. Aber aus irgendeinem Grund enthalten einige der von mir erstellten Arrays, die einfache Zeichenfolgen enthalten, auch automatisch einen zusätzlichen Wert, “equals: function”:
["Dummy1", "Dummy2", "Dummy3", equals: function]
Und immer wenn ich die Underscore.js-Schnittmethode für ein Array von Arrays verwende, bekomme ich immer [equals: function] in Entwicklungstools und nicht – wenn “Dummy3” allen Arrays gemeinsam ist – [“Dummy3”].
Also, TL; DR, gibt es eine andere Lösung für die Array-Schnittmenge, die für meinen Fall geeignet wäre? Und kann jemand erklären, was [equals: function] bedeutet hier? Wenn ich das Element in den Entwicklungstools erweitere, erzeugt es ein leeres Array und eine Liste von Methoden, die für Arrays verfügbar sind (Pop, Push, Shift usw.), aber diese Methoden werden alle ausgeblendet, während equals: function hervorgehoben wird.
Das Beispiel Underscore.js scheint etwas irreführend zu sein? Das letzte Array enthält nicht 43.
– Arg0n
19. Mai 16 um 10:22 Uhr
kk Ich werde das korrigieren :s
– Benutzer5102448
19. Mai 16 um 10:23 Uhr
Du hast ein , fehlt am Ende array2. Ich habe es gerade mit versucht _.intersection(array1, array2, array3, array4) in der lodash.com-Konsole und es funktioniert zurück "Lorem"
– Alberto Zaccagni
19. Mai 16 um 10:23 Uhr
Ich weiß nicht im Voraus, wie viele Divs mit Daten ich haben werde. Ich öffne ein Fenster und divs erscheinen. Also kann ich nicht einfach _.intersection(array1… array4) machen. Ich könnte sie jedoch durchlaufen und in ein einzelnes Array von Arrays schieben, wenn das Fenster geladen wird, aber das verursacht das Problem, mit dem ich in der zweiten Hälfte erkläre [equals: function].
var array1 = ["Lorem", "ipsum", "dolor"],
array2 = ["Lorem", "ipsum", "quick", "brown", "foo"],
array3 = ["Jumps", "Over", "Lazy", "Lorem"],
array4 = [1337, 420, 666, "Lorem"],
data = [array1, array2, array3, array4],
result = data.reduce((a, b) => a.filter(c => b.includes(c)));
console.log(result);
Was ist die mathematische Komplexität dieser Funktion? Sieht aus wie mindestens O(n²).
– herabgesetzt
8. März 19 um 3:36 Uhr
@ReactingToAngularVues, es ist nicht quadratisch, da das Teilergebnis für jede Schleife kürzer werden kann.
– Nina Scholz
5. April 19 um 11:13 Uhr
Ich denke O(n * log n) ist richtig. Ich denke, eine Sache, die diese Lösung noch weiter optimieren würde, ist, zuerst das kürzeste Array zu finden und es auf den ersten Index des Datenarrays zu verschieben. In der Reduce-Funktion verwenden wir das erste Element in data als Ausgangspunkt und prüfen dann jedes Element in diesem Array. Wenn dieses anfängliche Array das kürzestmögliche ist, werden zusätzliche Iterationen entfernt. Stellen Sie sich zum Beispiel vor, dass unser Datenarray so aussieht: [[1, 2, 3, …. , 10000], [1]]Das Vertauschen der Reihenfolge dieser beiden Elemente würde einen großen Unterschied machen. Tolle Lösung, @NinaScholz !
– Nathan
20. Mai 21 um 16:40 Uhr
Es ist Ω(mn) für insgesamt n Elemente nach der ersten Liste und m letzte Elemente, was die gleiche Art von Leistungsfalle ist wie typische versehentlich quadratische Dinge. Leicht verbessert mit a Set.
– Ry- ♦
10. November 21 um 5:54 Uhr
@ Nathan: Es ist definitiv nicht O (n log n).
– Ry- ♦
10. November 21 um 5:54 Uhr
Arg0n
Dazu habe ich eine Hilfsfunktion geschrieben:
function intersection() {
var result = [];
var lists;
if(arguments.length === 1) {
lists = arguments[0];
} else {
lists = arguments;
}
for(var i = 0; i < lists.length; i++) {
var currentList = lists[i];
for(var y = 0; y < currentList.length; y++) {
var currentValue = currentList[y];
if(result.indexOf(currentValue) === -1) {
var existsInAll = true;
for(var x = 0; x < lists.length; x++) {
if(lists[x].indexOf(currentValue) === -1) {
existsInAll = false;
break;
}
}
if(existsInAll) {
result.push(currentValue);
}
}
}
}
return result;
}
Eine etwas kleinere Implementierung Hier verwenden filter
Danke dafür. Ich kann ihm folgen und es funktioniert mit Dummy-Daten, buuuut … Ich habe keine separaten Arrays, die in Variablen wie Array1 und Array2 und Array3 gespeichert sind, weil ich im Voraus nicht weiß, wie viele Divs auf der Seite sind. Im Moment muss ich sie durchschleifen und in ein anderes Container-Array schieben. Ich konnte also nur Schnittpunkte (arrayContainingArrays) ausführen, die mit Ihrem Code nicht funktionieren würden. Das heißt, dies ist eine gute Lösung in Vanille-JavaScript, die jemand anderes verwenden könnte.
– Benutzer5102448
19. Mai ’16 um 10:48 Uhr
:O Okay! Gebt mir 5 Minuten, dann probiere ich das aus
– Benutzer5102448
19. Mai 16 um 10:54 Uhr
Dies funktioniert perfekt für Dummy-Arrays, aber nicht für die spezifischen Arrays, die ich möchte. Was bedeutet, dass mir an meiner Seite noch etwas fehlt. Aber diese Antwort ist eine gute Lösung, die meine Frage vollständig beantwortet und für andere nützlich sein wird. So gewinnen Sie heute das Internet.
– Benutzer5102448
19. Mai 16 um 11:09 Uhr
mit dem Datensatz: var array1 = [786, 796] var array2 = [100]; var array3 = [1]; var array4 = [2,3,4,1]; Die Ausgabe ist ein leeres Array, aber es sollten gemeinsame Werte sein. Bitte korrigieren Sie mich diesbezüglich. Danke schön.
– NN796
13. April 21 um 20:06 Uhr
@NN796 Sollte leer sein. In allen Arrays ist kein Wert vorhanden.
– Arg0n
15. April 21 um 5:25 Uhr
1983
Dies kann ziemlich kurz und bündig erfolgen, wenn Sie Rekursion und die neue ES2015-Syntax verwenden möchten:
const array1 = ["Lorem", "ipsum", "dolor"];
const array2 = ["Lorem", "ipsum", "quick", "brown", "foo"];
const array3 = ["Jumps", "Over", "Lazy", "Lorem"];
const array4 = [1337, 420, 666, "Lorem"];
const arrayOfArrays = [[4234, 2323, 43], [1323, 43, 1313], [23, 34, 43]];
// Filter xs where, for a given x, there exists some y in ys where y === x.
const intersect2 = (xs,ys) => xs.filter(x => ys.some(y => y === x));
// When there is only one array left, return it (the termination condition
// of the recursion). Otherwise first find the intersection of the first
// two arrays (intersect2), then repeat the whole process for that result
// combined with the remaining arrays (intersect). Thus the number of arrays
// passed as arguments to intersect is reduced by one each time, until
// there is only one array remaining.
const intersect = (xs,ys,...rest) => ys === undefined ? xs : intersect(intersect2(xs,ys),...rest);
console.log(intersect(array1, array2, array3, array4));
console.log(intersect(...arrayOfArrays));
// Alternatively, in old money,
var intersect2ES5 = function (xs, ys) {
return xs.filter(function (x) {
return ys.some(function (y) {
return y === x;
});
});
};
// Changed slightly from above, to take a single array of arrays,
// which matches the underscore.js approach in the Q., and is better anyhow.
var intersectES5 = function (zss) {
var xs = zss[0];
var ys = zss[1];
var rest = zss.slice(2);
if (ys === undefined) {
return xs;
}
return intersectES5([intersect2ES5(xs, ys)].concat(rest));
};
console.log(intersectES5([array1, array2, array3, array4]));
console.log(intersectES5(arrayOfArrays));
Hm. Nie zuvor auf const oder rest gestoßen. Ich sollte mich besser über ECMAScript 6 informieren, bevor mein Arbeitgeber mich durch einen Roboter ersetzt 😮
– Benutzer5102448
19. Mai ’16 um 16:34 Uhr
Mit einer Kombination aus Ideen mehrerer Mitwirkender und der neuesten ES6-Güte kam ich zu
const array1 = ["Lorem", "ipsum", "dolor"];
const array2 = ["Lorem", "ipsum", "quick", "brown", "foo"];
const array3 = ["Jumps", "Over", "Lazy", "Lorem"];
const array4 = [1337, 420, 666, "Lorem"];
Array.prototype.intersect = function intersect(a, ...b) {
const c = function (a, b) {
b = new Set(b);
return a.filter((a) => b.has(a));
};
return undefined === a ? this : intersect.call(c(this, a), ...b);
};
console.log(array1.intersect(array2, array3, array4));
// ["Lorem"]
Für alle, die das in Zukunft verwirrt,
_.intersection.apply(_, arrayOfArrays)
Ist in der Tat der eleganteste Weg, dies zu tun. Aber:
Das Beispiel Underscore.js scheint etwas irreführend zu sein? Das letzte Array enthält nicht 43.
– Arg0n
19. Mai 16 um 10:22 Uhr
kk Ich werde das korrigieren :s
– Benutzer5102448
19. Mai 16 um 10:23 Uhr
Du hast ein
,
fehlt am Endearray2
. Ich habe es gerade mit versucht_.intersection(array1, array2, array3, array4)
in der lodash.com-Konsole und es funktioniert zurück"Lorem"
– Alberto Zaccagni
19. Mai 16 um 10:23 Uhr
Ich weiß nicht im Voraus, wie viele Divs mit Daten ich haben werde. Ich öffne ein Fenster und divs erscheinen. Also kann ich nicht einfach _.intersection(array1… array4) machen. Ich könnte sie jedoch durchlaufen und in ein einzelnes Array von Arrays schieben, wenn das Fenster geladen wird, aber das verursacht das Problem, mit dem ich in der zweiten Hälfte erkläre [equals: function].
– Benutzer5102448
19. Mai ’16 um 10:25 Uhr