javascript arrays sorting

javascript - Ordenar números en orden descendente pero con `0`s al inicio



arrays sorting (10)

En lugar de proponer una nueva solución (ya hay varias aquí), me gustaría explicar la falla con la suya.

Cuando tu lo hagas:

if (x !== 0) { return 1; } if (x === 0) { return -1; }

¡Estás cubriendo prácticamente todas las situaciones posibles! Entonces, el return y - x nunca se alcanza. Podemos demostrar fácilmente que (el mensaje console.log no aparecerá):

arr = [0, 0, 0, 0, 0, 5, 4, 3, 2, 1] arr.sort((x, y) => { if (x !== 0) { return 1; } if (x === 0) { return -1; } console.log("I will never show up") return y - x; });

Por lo tanto, manteniéndolo lo más cerca posible de su código, debería ser:

arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5]; arr.sort((x, y) => { if (x === 0) { return -1; } if (y === 0) { return 1; } return y - x; }); console.log(arr)

Como puede ver, la diferencia con su código es de solo 1 carácter ( ! = ), por lo que ahora estamos probando que cualquiera de los números en la comparación sea cero.

Tengo un desafío en JavaScript que ya estoy tratando de resolver por un tiempo.

Considere esta matriz:

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5];

Tengo que dar salida a este resultado:

arr = [0, 0, 0, 0, 0, 5, 4, 3, 2, 1]

Estoy siguiendo esta línea de lógica para colocar los ceros al frente, ajustando el valor del índice:

arr.sort((x, y) => { if (x !== 0) { return 1; } if (x === 0) { return -1; } return y - x; });

Pero estoy atrapado en este resultado:

arr = [0, 0, 0, 0, 0, 1, 2, 3, 4, 5]

¿Alguien tiene algún consejo sobre cómo resolver esto?


No escriba su propia ordenación numérica si ya existe. Lo que quieres hacer es exactamente lo que dices en el título; ordenar los números en orden descendente, excepto los ceros al comienzo.

const zeroSort = arr => [...arr.filter(n => n == 0), ...new Float64Array(arr.filter(n => n != 0)).sort().reverse()]; console.log(zeroSort([0, 1, 0, 2, 0, 3, 0, 4, 0, 500]));

No escriba ningún código que no necesite; Puede que te equivoques.

Elija el TypedArray según el tipo de números que desea que maneje el TypedArray . Float64 es un buen valor predeterminado ya que maneja todos los números JS normales.


No estoy jugando código de golf aquí:

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5, -1]; arr.sort(function(a, b) { if (a === 0 && b !== 0) { // a is zero b is nonzero, a goes first return -1; } else if (a !== 0 && b === 0) { // a is nonzero b is zero, b goes first return 1; } else { // both are zero or both are nonzero, sort descending return b - a; } }); console.log(arr.toString());


Pruébelo ordenando la matriz en otro momento.

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5]; arr.sort((x, y) => { return y > x ? 1 : -1; }).sort((x, y) => { if (x === 0) { return -1; } return 0; })


Puede ordenar por el delta de b y a (para la clasificación descendente) y tomar Number.MAX_VALUE , para valores falsos como cero.

Number.MAX_VALUE - Number.MAX_VALUE

es igual a cero

let array = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5]; array.sort((a, b) => (b || Number.MAX_VALUE) - (a || Number.MAX_VALUE)); console.log(...array);


Puedes hacer esto así

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5]; let result = arr.sort((a,b) => { if(a == 0 || b == 0) return a-b; return b-a; }) console.log(result)

o puedes hacer esto

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5]; let result = arr.sort().sort((a,b) => { if(a > 0 && b > 0) return b-a return 0 }) console.log(result)


Quizás este código te ayude.

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5]; let arr1 = arr.filter(item => item === 0); let arr2 = arr.filter(item => item != 0); arr2 = arr2.sort(); arr2 = arr2.reverse(); let result = [...arr1, ...arr2] console.log(result);


Si le importa la eficiencia, probablemente sea más rápido filtrar los ceros primero . No querrá perder el tiempo ni siquiera mirarlos, y mucho menos agregar trabajo adicional a su devolución de llamada de comparación para manejar ese caso especial.

Especialmente si espera un número significativo de ceros, una pasada sobre los datos para filtrarlos debería ser mucho mejor que hacer una clasificación O (N log N) más grande que analizará cada cero varias veces.

Puede anteponer efficiently el número correcto de ceros una vez que haya terminado.

También es igual de fácil leer el código resultante. Utilicé TypedArray porque es eficiente y facilita la clasificación numérica . Pero puede usar esta técnica con Array regular, usando el idioma estándar de (a,b)=>ab para .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); */

No sé si TypedArray .sort() y luego .reverse es más rápido que usar una función de comparación personalizada para ordenar en orden descendente. O si podemos copiar y revertir sobre la marcha con un iterador.

También vale la pena considerarlo: solo use un TypedArray de longitud completa .

En lugar de usar .filter , .filter e intercambia los ceros al frente de la matriz a medida que avanzas. Esto toma una pasada sobre sus datos.

Luego use .subarray() para obtener una nueva vista TypedArray de los elementos distintos de cero del mismo ArrayBuffer subyacente. Clasificación que le dejará la matriz completa con un inicio cero y una cola ordenada, con la clasificación solo mirando los elementos que no son cero.

No vi una función de partición en los métodos Array o TypedArray, pero apenas conozco JavaScript. Con un buen JIT, un bucle no debería ser mucho peor que un método incorporado. (Especialmente cuando ese método involucra una devolución de llamada como .filter , y a menos que use realloc debajo del capó para reducir, tiene que averiguar cuánta memoria asignar antes de que realmente se filtre).

.filter() regular-Array .filter() antes de convertir a un TypedArray. Si su entrada ya es un TypedArray, no tiene este problema, y ​​esta estrategia se vuelve aún más atractiva.


Simplemente modifique la condición de su función de comparación de esta manera:

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5]; arr.sort((a, b) => { if(a && b) return b-a; return a-b; }); console.log(arr);


Como dice mdn docs:

Si ayb son dos elementos que se comparan, entonces:

Si compareFunction(a, b) devuelve menos de 0 , ordene a a un índice menor que b (es decir, a viene primero).

Si compareFunction(a, b) devuelve 0, deje a y b sin cambios entre sí, pero ordenados con respecto a todos los elementos diferentes. Nota: el estándar ECMAscript no garantiza este comportamiento, por lo tanto, no todos los navegadores (por ejemplo, las versiones de Mozilla que datan de al menos 2003) lo respetan.

Si compareFunction(a, b) devuelve mayor que 0, ordene b a un índice menor que a (es decir, b es lo primero).

compareFunction(a, b) siempre debe devolver el mismo valor cuando se le da un par específico de elementos b como sus dos argumentos. Si se devuelven resultados inconsistentes, el orden de clasificación no está definido.

Entonces, la función de comparación tiene la siguiente forma:

function compare(a, b) { if (a is less than b by some ordering criterion) { return -1; } if (a is greater than b by the ordering criterion) { return 1; } // a must be equal to b return 0; }

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5]; arr.sort((x, y) => { if (x > 0 && y > 0) { return y - x; } return x - y; }); console.log(arr);