Tengo una lista de elementos de tipo PartiePos ... simplemente con ese esquema:
{ ID: string } Ahora, tengo dos listas más de elementos de tipo string .
Aquí las tres listas:
items = [{ID: "123"}, {ID: "234"}, {ID: "345"}, {ID: "456"}, {ID: "567"}] assigned = ["123", "345"] disabled = ["567", "234"]Quiero ordenarlos de acuerdo con este esquema:
Resolvería mis listas en esta salida ordenada:
"456" "123" "345" "234" "567"Logro esto aplicando estos dos comparadores a la clasificación de mi lista:
const comparatorA = (a: PartiePos, b: PartiePos) => { if (assigned.includes(a.ID) && assigned.includes(b.ID)) { return 0 } if (assigned.includes(a.ID) && ! assigned.includes(b.ID)) { return 1 } if (! assigned.includes(a.ID) && assigned.includes(b.ID)) { return -1 } } const comparatorD = (a: PartiePos, b: PartiePos) => { if (disabled.includes(a.ID) && disabled.includes(b.ID)) { return 0 } if (disabled.includes(a.ID) && ! disabled.includes(b.ID)) { return 1 } if (! disabled.includes(a.ID) && disabled.includes(b.ID)) { return -1 } } [...] return items.sort(comparatorA).sort(comparatorD)Pero la clasificación es bastante lenta y bloquea mi sitio, la consola de desarrollo me dice que tengo una mutación recursiva y esto provoca el bloqueo de javascript.
¿Alguna idea de cómo mejorar esto?
No hay necesidad de ordenar aquí ya que tomaría tiempo O(n log n) . Puede filtrar los elementos deshabilitados y asignados, luego concatenar solo esos elementos:
const items = [{ID: "123"}, {ID: "234"}, {ID: "345"}, {ID: "456"}, {ID: "567"}]; // If these are long, use a JS `new Set` object for fast lookup; const assigned = ["123", "345"]; const disabled = ["567", "234"]; // just those that keep their regular place const withoutAssignedAndDisabled = items.filter(x => !assigned.includes(x.ID) && !disabled.includes(x.ID)); // concat the assigned and then disabled const result = withoutAssignedAndDisabled.concat( items.filter(x => assigned.includes(x.ID)) ).concat( items.filter(x => disabled.includes(x.ID)) );Se me ocurrió un enfoque interesante, volví a publicarlo y vi que Benjamin Gruenbaum había dado una respuesta mucho mejor.
Pero esto sigue siendo interesante, y creo que podría ser útil para varios escenarios, así que lo publicaré:
const using = ((table) => (assigned, disabled) => ( {ID: x}, {ID: y}, kx = assigned .includes (x) ? 'a' : disabled .includes (x) ? 'd' : '_', ky = assigned .includes (y) ? 'a' : disabled .includes (y) ? 'd' : '_', ) => table [kx] [ky])({ //x↓ y→ a: {a: 0, d: -1, _: 1}, d: {a: 1, d: 0, _: -1}, _: {a: -1, d: 1, _: 0} }) const items = [{ID: "123"}, {ID: "234"}, {ID: "345"}, {ID: "456"}, {ID: "567"}] const assigned = ["123", "345"] const disabled = ["567", "234"] console .log (items .sort (using (assigned, disabled))) .as-console-wrapper {max-height: 100% !important; top: 0} Aquí usamos una tabla de búsqueda en claves simples derivadas de las categorías assigned y disabled (suponiendo que se excluyen mutuamente).
Para manejar los casos en los que tenemos dos en la misma categoría, aprovechamos el hecho de que todos los motores JS modernos son estables y solo devuelven 0 .
Claramente, podríamos hacer esto con una matriz de matrices en lugar de las letras de categoría, pero creo que esto es más claro y nos permitiría ser más explícitos si queremos, eligiendo usar "asignado"/"derivado"/"ninguno" en lugar de "a"/"d"/"_". En cualquier caso, la matriz de resultados debe ser antisimétrica para que tenga sentido.
Es fácil imaginar una generalización de esto que acepte una función que genere una clave y una tabla que explique el resultado de la clasificación para cualquier par de categorías. Pero como Benjamin ya dio la respuesta definitiva, eso lo dejo para otro día.