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);
Si ayb son dos elementos que se comparan, entonces:
Si
compareFunction(a, b)
devuelve menos de0
, ordenea
a un índice menor queb
(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, ordeneb
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 elementosb
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);