Dada una matriz de objetos llamada allItems que está preordenada, pero que no se puede volver a ordenar a partir de la información que contiene, ¿cuál es una implementación alternativa a la función de reducción a continuación que retendrá el orden ordenado de allItems ?
La lógica a continuación generará:
[{ id: 'd' }, { id: 'a' }, { id: 'b' }]La salida deseada es:
[{ id: 'a' }, { id: 'b' }, { id: 'd' }] // NOTE: allItems is pre-sorted, but lacks the information to re-sort it const allItems = [{id:'a'}, {id:'b'}, {id:'c'}, {id:'d'}, {id:'e'}, {id:'f'}]; const includedIds = ['d', 'a', 'b']; // QUESTION: How to create the same output, but in the order they appear in allItems const unsortedIncludedItems = includedIds.reduce((accumulator, id) => { const found = allItems.find(n => n.id === id); if (found) accumulator.push(found); return accumulator; }, [])Como se mencionó en respuesta a @Ben, simplemente invertir la lógica es un factor decisivo por razones de rendimiento.
El problema que tiene aquí es que su código invierte la lista. En su lugar, simplemente puede pasar al frente de la lista y se mantendrá el orden original.
Desafortunadamente, pasar al frente de una lista es más lento, es O(n) en lugar de O(1). Parece que se supone que Array.prototype.unshift es más rápido , pero sigue siendo O(n) según este blog . Suponiendo que la cantidad de elementos encontrados sea pequeña, no notará ningún problema de rendimiento. En ese caso, reemplace push con unshift así:
// NOTE: allItems is pre-sorted, but lacks the information to re-sort it const allItems = [{id:'a'}, {id:'b'}, {id:'c'}, {id:'d'}, {id:'e'}, {id:'f'}]; const includedIds = ['d', 'a', 'b']; // QUESTION: How to create the same output, but in the order they appear in allItems const unsortedIncludedItems = includedIds.reduce((accumulator, id) => { const found = allItems.find(n => n.id === id); if (found) accumulator.unshift(found); return accumulator; }, [])De lo contrario, estas son tus opciones:
Cree un envoltorio alrededor de este objeto que invierta los índices en lugar de la matriz. Esto se puede hacer con una función como esta:
const getFromEnd = (arr, i) => arr[arr.longitud - 1 - i]
Tenga en cuenta que esto se puede reemplazar con arr.at(-i) en las nuevas versiones del navegador (últimos meses). Esto podría encapsularse dentro de una clase si te sientes inclinado a OOP.
El ejemplo B utilizará el índice de la matriz de entrada para ordenar la matriz filtrada.
Pruebe .filter() e .include() para obtener los objetos deseados y luego .sort() por el valor de cadena de cada objeto. Vea el Ejemplo A.
Otra forma es usar .flatMap() e .include() para obtener una matriz de matrices.
// each index is from the original array [ [15, {id: 'x'}], [0, {id: 'z'}], [8, {id: 'y'}] ]
Luego use .sort() en cada índice de subarreglo.
[ [0, {id: 'z'}], [8, {id: 'y'}], [15, {id: 'x'}] ]
Finalmente, use .flatMap() una vez más para extraer los objetos y aplanar la matriz de matrices en una matriz de objetos.
[ {id: 'z'}, {id: 'y'}, {id: 'x'} ]
Ver Ejemplo B
const all = [{id:'a'}, {id:'b'}, {id:'c'}, {id:'d'}, {id:'e'}, {id:'f'}]; const values = ['d', 'a', 'b']; const sortByStringValue = (array, vArray, key) => array.filter(obj => vArray.includes(obj[key])).sort((a, b) => a[key].localeCompare(b[key])); console.log(JSON.stringify(sortByStringValue(all, values, 'id'))); const all = [{id:'a'}, {id:'b'}, {id:'c'}, {id:'d'}, {id:'e'}, {id:'f'}]; const values = ['d', 'a', 'b']; const alt = [{name:'Matt'}, {name:'Joe'}, {name:'Jane'}, {name:'Lynda'}, {name:'Shelly'}, {name:'Alice'}]; const filter = ['Shelly', 'Matt', 'Lynda']; const sortByIndex = (array, vArray, key) => array.flatMap((obj, idx) => vArray.includes(obj[key]) ? [[idx, obj]] : []).sort((a, b) => a[0] - b[0]).flatMap(sub => [sub[1]]); console.log(JSON.stringify(sortByIndex(all, values, 'id'))); console.log(JSON.stringify(sortByIndex(alt, filter, 'name')));En lugar de iterar sobre los includedIds (en el orden incorrecto) y ver si puede encontrarlos en allItems , simplemente itere sobre allItems (que es el orden correcto) y vea si puede encontrar sus ids en includedIds :
const allItems = [{id:'a'}, {id:'b'}, {id:'c'}, {id:'d'}, {id:'e'}, {id:'f'}]; const includedIds = ['d', 'a', 'b']; const includedItems = allItems.filter(item => includedIds.includes(item.id));