Si vous vous souciez de l'efficacité, il est probablement plus rapide de filtrer les zéros en premier . Vous ne voulez sort
pas perdre de temps, même en les regardant, sans parler d'ajouter du travail supplémentaire à votre rappel de comparaison pour gérer ce cas spécial.
Surtout si vous vous attendez à un nombre important de zéros, un passage sur les données pour les filtrer devrait être bien mieux que de faire un tri O (N log N) plus grand qui examinera chaque zéro plusieurs fois.
Vous pouvez ajouter efficacement le bon nombre de zéros après avoir terminé.
Il est également tout aussi facile de lire le code résultant. J'ai utilisé TypedArray car il est efficace et facilite le tri numérique . Mais vous pouvez utiliser cette technique avec un tableau standard, en utilisant l'idiome standard de (a,b)=>a-b
for .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);
*/
Je ne sais pas si TypedArray .sort()
puis .reverse
est plus rapide que d'utiliser une fonction de comparaison personnalisée pour trier par ordre décroissant. Ou si nous pouvons copier et inverser à la volée avec un itérateur.
À considérer également: n'utilisez qu'un seul TypedArray de toute la longueur .
Au lieu de l'utiliser .filter
, faites une boucle dessus et permutez les zéros à l'avant du tableau au fur et à mesure. Cela prend un seul passage sur vos données.
Ensuite, utilisez .subarray()
pour obtenir une nouvelle vue TypedArray des éléments non nuls du même ArrayBuffer sous-jacent. Un tri qui vous laissera le tableau complet avec un début zéro et une queue triée, le tri ne regardant que les éléments non nuls.
Je n'ai pas vu de fonction de partition dans les méthodes Array ou TypedArray, mais je connais à peine JavaScript. Avec un bon JIT, une boucle ne devrait pas être bien pire qu'une méthode intégrée. (Surtout lorsque cette méthode implique un rappel .filter
, et à moins qu'elle n'utilise realloc
sous le capot pour rétrécir, elle doit déterminer la quantité de mémoire à allouer avant qu'elle ne filtre réellement).
J'ai utilisé regular-Array .filter()
avant de convertir en TypedArray. Si votre entrée est déjà un TypedArray, vous n'avez pas ce problème et cette stratégie devient encore plus attrayante.