Se você se preocupa com eficiência, provavelmente é mais rápido filtrar os zeros primeiro . Você não quer sort
perder tempo olhando para eles, muito menos adicionando trabalho extra ao seu retorno de chamada de comparação para lidar com esse caso especial.
Especialmente se você espera um número significativo de zeros, uma passagem sobre os dados para filtrá-los deve ser muito melhor do que fazer uma classificação O (N log N) maior que analisará cada zero várias vezes.
Você pode acrescentar com eficiência o número certo de zeros depois de terminar.
Também é fácil ler o código resultante. Usei o TypedArray porque é eficiente e facilita a classificação numérica . Mas você pode usar essa técnica com Array regular, usando o idioma padrão 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);
*/
Não sei se TypedArray .sort()
e, em seguida, .reverse
é mais rápido do que usar uma função de comparação personalizada para classificar em ordem decrescente. Ou se pudermos copiar e reverter em tempo real com um iterador.
Também vale a pena considerar: use apenas um TypedArray de todo o comprimento .
Em vez de usar .filter
, faça um loop sobre ele e troque os zeros para a frente da matriz à medida que avança. Isso leva uma passagem sobre seus dados.
Em seguida, use .subarray()
para obter uma nova exibição TypedArray dos elementos diferentes de zero do mesmo ArrayBuffer subjacente. Classificação que deixará a matriz completa com um início zero e uma cauda classificada, com a classificação apenas olhando para os elementos diferentes de zero.
Não vi uma função de partição nos métodos Array ou TypedArray, mas mal conheço JavaScript. Com um bom JIT, um loop não deve ser muito pior do que um método interno. (Especialmente quando esse método envolve um retorno de chamada .filter
e, a menos que ele use realloc
sob o capô para diminuir, ele precisa descobrir quanta memória alocar antes de realmente filtrar).
Eu usei Array regular .filter()
antes de converter para um TypedArray. Se sua entrada já é um TypedArray, você não tem esse problema, e essa estratégia se torna ainda mais atraente.