¿Es posible ordenar las entradas de un objeto de mapa es6?
var map = new Map();
map.set('2-1', foo);
map.set('0-1', bar);
resulta en:
map.entries = {
0: {"2-1", foo },
1: {"0-1", bar }
}
¿Es posible ordenar las entradas según sus claves?
map.entries = {
0: {"0-1", bar },
1: {"2-1", foo }
}
javascript
ecmascript-6
Ivan Bacher
fuente
fuente
Respuestas:
Según la documentación de MDN:
Puedes hacerlo de esta manera:
var map = new Map(); map.set('2-1', "foo"); map.set('0-1', "bar"); map.set('3-1', "baz"); var mapAsc = new Map([...map.entries()].sort()); console.log(mapAsc)
Al usar
.sort()
, recuerde que la matriz se ordena de acuerdo con el valor del punto de código Unicode de cada carácter, de acuerdo con la conversión de cadena de cada elemento. Por2-1, 0-1, 3-1
lo que se ordenará correctamente.fuente
var mapAsc = new Map([...map.entries()].sort((a,b) => a[0] > b[0]));
usando la función de flecha (lambda)2-1,foo
con0-1,bar
y3-1,baz
(a,b) => a[0] > b[0]
!...
puntos son importantes, de lo contrario, está intentando ordenar un MapIterator1e-9
se colocan después100
en el mapa ordenado. Código que funciona con números:new Map([...map.entries()].sort((e1, e2) => e1[0] - e2[0]))
Respuesta corta
new Map([...map].sort((a, b) => // Some sort function comparing keys with a[0] b[0] or values with a[1] b[1] // Be sure to return -1 if lower and, if comparing values, return 0 if equal ))
Por ejemplo, al comparar cadenas de valor, que pueden ser iguales, pasamos una función de ordenación que accede a [1] y tiene una condición igual que devuelve 0:
new Map([...map].sort((a, b) => (a[1] > b[1] && 1) || (a[1] === b[1] ? 0 : -1)))
Comparando cadenas de claves, que no pueden ser iguales (claves de cadenas idénticas se sobrescriben entre sí), podemos omitir la condición de iguales. Sin embargo, deberíamos devolver explícitamente -1, porque devolver un perezoso
a[0] > b[0]
incorrectamente da falso (tratado como 0, es decir, igual) cuandoa[0] < b[0]
:new Map([...map].sort((a, b) => a[0] > b[0] ? 1 : -1))
En detalle con ejemplos
El
.entries()
in[...map.entries()]
(sugerido en muchas respuestas) es redundante, probablemente agregue una iteración adicional del mapa a menos que el motor JS lo optimice para usted.En el caso de prueba simple, puede hacer lo que pide la pregunta con:
new Map([...map].sort())
... que, si las claves son todas cadenas, compara cadenas de valor-clave unidas por comas comprimidas y coaccionadas como
'2-1,foo'
y'0-1,[object Object]'
, devolviendo un nuevo mapa con el nuevo orden de inserción:Nota: si solo ve
{}
la salida de la consola de SO, busque en la consola de su navegador realconst map = new Map([ ['2-1', 'foo'], ['0-1', { bar: 'bar' }], ['3-5', () => 'fuz'], ['3-2', [ 'baz' ]] ]) console.log(new Map([...map].sort()))
SIN EMBARGO , no es una buena práctica confiar en la coerción y la cadena de caracteres como esta. Puede obtener sorpresas como:
const map = new Map([ ['2', '3,buh?'], ['2,1', 'foo'], ['0,1', { bar: 'bar' }], ['3,5', () => 'fuz'], ['3,2', [ 'baz' ]], ]) // Compares '2,3,buh?' with '2,1,foo' // Therefore sorts ['2', '3,buh?'] ******AFTER****** ['2,1', 'foo'] console.log('Buh?', new Map([...map].sort())) // Let's see exactly what each iteration is using as its comparator for (const iteration of map) { console.log(iteration.toString()) }
Errores como este son realmente difíciles de depurar, ¡no se arriesgue!
Si desea ordenar por claves o valores, es mejor acceder a ellos explícitamente con
a[0]
yb[0]
en la función de ordenación, como esta. Tenga en cuenta que deberíamos regresar-1
y1
para antes y después, nofalse
o0
como con rawa[0] > b[0]
porque eso se trata como iguales:const map = new Map([ ['2,1', 'this is overwritten'], ['2,1', '0,1'], ['0,1', '2,1'], ['2,2', '3,5'], ['3,5', '2,1'], ['2', ',9,9'] ]) // For keys, we don't need an equals case, because identical keys overwrite const sortStringKeys = (a, b) => a[0] > b[0] ? 1 : -1 // For values, we do need an equals case const sortStringValues = (a, b) => (a[1] > b[1] && 1) || (a[1] === b[1] ? 0 : -1) console.log('By keys:', new Map([...map].sort(sortStringKeys))) console.log('By values:', new Map([...map].sort(sortStringValues)))
fuente
Convertir
Map
a una matriz usandoArray.from
, ordenar matriz, convertir de nuevo aMap
, por ejemplonew Map( Array .from(eventsByDate) .sort((a, b) => { // a[0], b[0] is the key of the map return a[0] - b[0]; }) )
fuente
[...map.values()].sort()
no funcionó para mí, peroArray.from(map.values()).sort()
síLa idea es extraer las claves de su mapa en una matriz. Ordene esta matriz. Luego, itere sobre esta matriz ordenada, obtenga su par de valores del mapa sin clasificar y colóquelos en un nuevo mapa. El nuevo mapa estará ordenado. El siguiente código es su implementación:
var unsortedMap = new Map(); unsortedMap.set('2-1', 'foo'); unsortedMap.set('0-1', 'bar'); // Initialize your keys array var keys = []; // Initialize your sorted maps object var sortedMap = new Map(); // Put keys in Array unsortedMap.forEach(function callback(value, key, map) { keys.push(key); }); // Sort keys array and go through them to put in and put them in sorted map keys.sort().map(function(key) { sortedMap.set(key, unsortedMap.get(key)); }); // View your sorted map console.log(sortedMap);
fuente
unsortedMap.keys()
. Tambiénkeys.sort().map...
debería serlokeys.sort().forEach...
.Puede convertir a una matriz y llamar a los métodos de selección de matriz en ella:
[...map].sort(/* etc */);
fuente
Desafortunadamente, no se implementó realmente en ES6. Tiene esta función con OrderedMap.sort () de ImmutableJS o _.sortBy () de Lodash.
fuente
Una forma es obtener la matriz de entradas, ordenarla y luego crear un nuevo mapa con la matriz ordenada:
let ar = [...myMap.entries()]; sortedArray = ar.sort(); sortedMap = new Map(sortedArray);
Pero si no desea crear un nuevo objeto, sino trabajar en el mismo, puede hacer algo como esto:
// Get an array of the keys and sort them let keys = [...myMap.keys()]; sortedKeys = keys.sort(); sortedKeys.forEach((key)=>{ // Delete the element and set it again at the end const value = this.get(key); this.delete(key); this.set(key,value); })
fuente
El fragmento a continuación ordena el mapa dado por sus claves y asigna las claves a los objetos de valor-clave nuevamente. Usé la función localeCompare ya que mi mapa era string-> string object map.
var hash = {'x': 'xx', 't': 'tt', 'y': 'yy'}; Object.keys(hash).sort((a, b) => a.localeCompare(b)).map(function (i) { var o = {}; o[i] = hash[i]; return o; });
resultado:
[{t:'tt'}, {x:'xx'}, {y: 'yy'}];
fuente
Por lo que veo, actualmente no es posible ordenar un mapa correctamente.
Las otras soluciones donde el mapa se convierte en una matriz y se ordena de esta manera tienen el siguiente error:
var a = new Map([[1, 2], [3,4]]) console.log(a); // a = Map(2) {1 => 2, 3 => 4} var b = a; console.log(b); // b = Map(2) {1 => 2, 3 => 4} a = new Map(); // this is when the sorting happens console.log(a, b); // a = Map(0) {} b = Map(2) {1 => 2, 3 => 4}
La clasificación crea un nuevo objeto y todos los demás indicadores del objeto sin clasificar se rompen.
fuente
2 horas dedicadas a entrar en detalles.
Tenga en cuenta que la respuesta a la pregunta ya se encuentra en https://stackoverflow.com/a/31159284/984471
Sin embargo, la cuestión tiene teclas que no son los habituales,
Un claro ejemplo de ello y en general con la explicación, se encuentra por debajo que proporciona un poco más de claridad:
.
let m1 = new Map(); m1.set(6,1); // key 6 is number and type is preserved (can be strings too) m1.set(10,1); m1.set(100,1); m1.set(1,1); console.log(m1); // "string" sorted (even if keys are numbers) - default behaviour let m2 = new Map( [...m1].sort() ); // ...is destructuring into individual elements // then [] will catch elements in an array // then sort() sorts the array // since Map can take array as parameter to its constructor, a new Map is created console.log('m2', m2); // number sorted let m3 = new Map([...m1].sort((a, b) => { if (a[0] > b[0]) return 1; if (a[0] == b[0]) return 0; if (a[0] < b[0]) return -1; })); console.log('m3', m3); // Output // Map { 6 => 1, 10 => 1, 100 => 1, 1 => 1 } // m2 Map { 1 => 1, 10 => 1, 100 => 1, 6 => 1 } // Note: 1,10,100,6 sorted as strings, default. // Note: if the keys were string the sort behavior will be same as this // m3 Map { 1 => 1, 6 => 1, 10 => 1, 100 => 1 } // Note: 1,6,10,100 sorted as number, looks correct for number keys
Espero que ayude.
fuente
Quizás un ejemplo más realista sobre no ordenar un objeto Mapa, sino preparar la clasificación por adelantado antes de hacer el Mapa. La sintaxis se vuelve bastante compacta si lo haces así. Puede aplicar la clasificación antes de la función de mapa de esta manera, con una función de clasificación antes del mapa (Ejemplo de una aplicación React en la que estoy trabajando usando la sintaxis JSX)
Marque que aquí defino una función de clasificación en el interior usando una función de flecha que devuelve -1 si es más pequeña y 0, de lo contrario, ordenada en una propiedad de los objetos Javascript en la matriz que obtengo de una API.
report.ProcedureCodes.sort((a, b) => a.NumericalOrder < b.NumericalOrder ? -1 : 0).map((item, i) => <TableRow key={i}> <TableCell>{item.Code}</TableCell> <TableCell>{item.Text}</TableCell> {/* <TableCell>{item.NumericalOrder}</TableCell> */} </TableRow> )
fuente
let map = new Map(); map.set('2-1', "foo"); map.set('0-1', "bar"); map.set('3-1', "baz"); let mapAsc = new Map([...map.entries()].sort()); console.log(mapAsc); // Map(3) {"0-1" => "bar", "2-1" => "foo", "3-1" => "baz"}
fuente