Wenn Sie Wert auf Effizienz legen, ist es wahrscheinlich am schnellsten, zuerst die Nullen herauszufiltern . Sie möchten keine sort
Zeit damit verschwenden, sie sich anzusehen, geschweige denn Ihrem Vergleichsrückruf zusätzliche Arbeit hinzuzufügen, um diesen Sonderfall zu behandeln.
Insbesondere wenn Sie eine signifikante Anzahl von Nullen erwarten, sollte ein Durchlauf über die Daten zum Herausfiltern viel besser sein als eine größere O (N log N) -Sortierung, bei der jede Null mehrmals betrachtet wird.
Sie können die richtige Anzahl von Nullen effizient voranstellen, nachdem Sie fertig sind.
Genauso einfach ist es, den resultierenden Code zu lesen. Ich habe TypedArray verwendet, weil es effizient ist und das numerische Sortieren vereinfacht . Sie können diese Technik jedoch mit regulären Arrays verwenden, wobei Sie die Standardsprache (a,b)=>a-b
for verwenden .sort
.
let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5];
let nonzero_arr = Int32Array.from(arr.filter(n => n != 0));
let zcount = arr.length - nonzero_arr.length;
nonzero_arr.sort(); // numeric TypedArray sorts numerically, not alphabetically
// Reverse the sorted part before copying into the final array.
nonzero_arr.reverse();
// efficient-ish TypedArray for main result
let revsorted = new Int32Array(arr.length); // zero-filled full size
revsorted.set(nonzero_arr, zcount); // copy after the right number of zeros
console.log(Array.from(revsorted)); // prints strangely for TypedArray, with invented "0", "1" keys
/*
// regular Array result
let sorted = [...Array(zcount).fill(0), ...nonzero_arr] // IDK if this is efficient
console.log(sorted);
*/
Ich weiß nicht, ob TypedArray .sort()
und dann .reverse
schneller als die Verwendung einer benutzerdefinierten Vergleichsfunktion zum Sortieren in absteigender Reihenfolge. Oder wenn wir mit einem Iterator im laufenden Betrieb kopieren und umkehren können.
Ebenfalls erwägenswert: Verwenden Sie nur ein TypedArray in voller Länge .
Anstatt zu verwenden .filter
, schleifen Sie darüber und tauschen Sie die Nullen an die Vorderseite des Arrays, während Sie fortfahren. Dies dauert einen Durchgang über Ihre Daten.
Verwenden Sie dann .subarray()
, um eine neue TypedArray-Ansicht der Nicht-Null-Elemente desselben zugrunde liegenden ArrayBuffers abzurufen. Durch die Sortierung erhalten Sie das gesamte Array mit einem Nullstart und einem sortierten Ende, wobei die Sortierung immer nur die Nicht-Null-Elemente betrachtet.
Ich habe keine Partitionsfunktion in den Array- oder TypedArray-Methoden gesehen, kenne aber kaum JavaScript. Mit einer guten JIT sollte eine Schleife nicht zu viel schlechter sein als eine integrierte Methode. (Insbesondere wenn diese Methode einen Rückruf wie beinhaltet .filter
und nicht realloc
unter der Haube zum Verkleinern verwendet wird, muss sie herausfinden, wie viel Speicher zugewiesen werden muss, bevor sie tatsächlich gefiltert wird.)
Ich habe .filter()
vor der Konvertierung in ein TypedArray ein reguläres Array verwendet. Wenn Ihre Eingabe bereits ein TypedArray ist, haben Sie dieses Problem nicht und diese Strategie wird noch attraktiver.