Tenho um desafio em JavaScript que já estou tentando descobrir há um tempo.
Considere esta matriz:
let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5];
Eu tenho que produzir este resultado:
arr = [0, 0, 0, 0, 0, 5, 4, 3, 2, 1]
Estou seguindo esta linha de lógica para posicionar os zeros na frente, ajustando o valor do índice:
arr.sort((x, y) => {
if (x !== 0) {
return 1;
}
if (x === 0) {
return -1;
}
return y - x;
});
Mas estou preso neste resultado:
arr = [0, 0, 0, 0, 0, 1, 2, 3, 4, 5]
Alguém tem alguma dica sobre como resolver isso?
javascript
arrays
sorting
lianbwl
fonte
fonte
return x - y;
?return y - x;
? Mesmo em javascript, não consigo pensar em nada que não fosse nem===0
nem!==0
.Respostas:
Você pode classificar pelo delta de
b
ea
(para classificação decrescente) e pegarNumber.MAX_VALUE
, para valores falsos como zero.Este:
é igual a zero.
fonte
NaN
se ambosa
eb
forem zero. Esse pode ser um comportamento indesejado.Array.prototype.sort
são definidos pela implementação se o comparador retornarNaN
, portanto, esse comparador é uma má ideia. Ele tenta ser inteligente e erra.Como mdn docs diz:
Se aeb são dois elementos comparados, então:
Portanto, a função de comparação tem o seguinte formato:
fonte
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
.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 userealloc
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.fonte
Apenas modifique a condição da sua função de comparação assim:
fonte
!a
ainda é verdadeira. Ele retornará-1
a=b=0
Não está a jogar golfe com códigos aqui:
fonte
Não escreva sua própria classificação numérica, se ela já existir. O que você quer fazer é exatamente o que você diz no título; classifique os números em ordem decrescente, exceto os zeros no início.
Não escreva nenhum código que não precise; você pode entender errado.
Escolha o TypedArray com base no tipo de número que você deseja que a matriz manipule. Float64 é um bom padrão, pois lida com todos os números JS normais.
fonte
Array(n).fill(0)
.let f64arr = new Float64Array(arr.filter(n => n != 0))
, então[ ...Array(arr.length - f64arr.length).fill(0),
... então adiciona 1 linha extra e simplifica a última linha.Você pode fazer isso assim:
ou você pode fazer isso:
fonte
fonte