Ordenar una matriz de JavaScript basada en otra matriz
¿Es posible ordenar y reorganizar una matriz similar a la siguiente?
itemsArray = [
['Anne', 'a'],
['Bob', 'b'],
['Henry', 'b'],
['Andrew', 'd'],
['Jason', 'c'],
['Thomas', 'b']
]
para que coincida con la disposición de esta matriz:
sortingArr = [ 'b', 'c', 'b', 'b', 'a', 'd' ]
Desafortunadamente, no tengo ninguna identificación para realizar un seguimiento. Necesitaría priorizar la matriz de elementos para que coincida con sortingArr lo más cerca posible.
Aquí está el resultado que estoy buscando:
itemsArray = [
['Bob', 'b'],
['Jason', 'c'],
['Henry', 'b'],
['Thomas', 'b']
['Anne', 'a'],
['Andrew', 'd'],
]
¿Cómo se puede hacer esto?
Respuesta de una línea.
itemsArray.sort(function(a, b){
return sortingArr.indexOf(a) - sortingArr.indexOf(b);
});
O incluso más corto:
itemsArray.sort((a, b) => sortingArr.indexOf(a) - sortingArr.indexOf(b));
Algo como:
items = [
['Anne', 'a'],
['Bob', 'b'],
['Henry', 'b'],
['Andrew', 'd'],
['Jason', 'c'],
['Thomas', 'b']
]
sorting = [ 'b', 'c', 'b', 'b', 'c', 'd' ];
result = []
sorting.forEach(function(key) {
var found = false;
items = items.filter(function(item) {
if(!found && item[1] == key) {
result.push(item);
found = true;
return false;
} else
return true;
})
})
result.forEach(function(item) {
document.writeln(item[0]) /// Bob Jason Henry Thomas Andrew
})
Aquí hay un código más corto, pero destruye la sorting
matriz:
result = items.map(function(item) {
var n = sorting.indexOf(item[1]);
sorting[n] = '';
return [n, item]
}).sort().map(function(j) { return j[1] })
Si usa la función de clasificación de matriz nativa, puede pasar un comparador personalizado para usarlo al ordenar la matriz. El comparador debe devolver un número negativo si el primer valor es menor que el segundo, cero si son iguales y un número positivo si el primer valor es mayor.
Entonces, si entiendo correctamente el ejemplo que estás dando, podrías hacer algo como:
function sortFunc(a, b) {
var sortingArr = [ 'b', 'c', 'b', 'b', 'c', 'd' ];
return sortingArr.indexOf(a[1]) - sortingArr.indexOf(b[1]);
}
itemsArray.sort(sortFunc);
Caso 1: Pregunta original (sin bibliotecas)
Muchas otras respuestas que funcionan. :)
Caso 2: Pregunta original (Lodash.js o Underscore.js)
var groups = _.groupBy(itemArray, 1);
var result = _.map(sortArray, function (i) { return groups[i].shift(); });
Caso 3: Ordenar Array1 como si fuera Array2
Supongo que la mayoría de la gente vino aquí buscando un equivalente a array_multisort de PHP (yo lo hice), así que pensé en publicar esa respuesta también. Hay un par de opciones:
1. Existe una implementación JS de array_multisort() . Gracias a @Adnan por señalarlo en los comentarios. Aunque es bastante grande.
2. Escribe el tuyo propio. ( Demostración de JSFiddle )
function refSort (targetData, refData) {
// Create an array of indices [0, 1, 2, ...N].
var indices = Object.keys(refData);
// Sort array of indices according to the reference data.
indices.sort(function(indexA, indexB) {
if (refData[indexA] < refData[indexB]) {
return -1;
} else if (refData[indexA] > refData[indexB]) {
return 1;
}
return 0;
});
// Map array of indices to corresponding values of the target array.
return indices.map(function(index) {
return targetData[index];
});
}
3. Lodash.js o Underscore.js (ambas bibliotecas populares y más pequeñas que se centran en el rendimiento) ofrecen funciones auxiliares que le permiten hacer esto:
var result = _.chain(sortArray)
.pairs()
.sortBy(1)
.map(function (i) { return itemArray[i[0]]; })
.value();
... Lo que (1) agrupará sortArray en [index, value]
pares, (2) los ordenará por valor (también puede proporcionar una devolución de llamada aquí), (3) reemplazará cada uno de los pares con el elemento de itemArray en el índice del par se originó de.