Est-il possible de trier les entrées d'un objet de carte es6?
var map = new Map();
map.set('2-1', foo);
map.set('0-1', bar);
résulte en:
map.entries = {
0: {"2-1", foo },
1: {"0-1", bar }
}
Est-il possible de trier les entrées en fonction de leurs clés?
map.entries = {
0: {"0-1", bar },
1: {"2-1", foo }
}
javascript
ecmascript-6
Ivan Bacher
la source
la source
Réponses:
Selon la documentation MDN:
Vous pouvez le faire de cette façon:
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)
En utilisant
.sort()
, rappelez-vous que le tableau est trié en fonction de la valeur du point de code Unicode de chaque caractère, en fonction de la conversion de chaîne de chaque élément. Alors2-1, 0-1, 3-1
sera trié correctement.la source
var mapAsc = new Map([...map.entries()].sort((a,b) => a[0] > b[0]));
utilisant la fonction de flèche (lambda)2-1,foo
à0-1,bar
et3-1,baz
(a,b) => a[0] > b[0]
!...
points sont importants sinon vous essayez de trier un MapIterator1e-9
être mis après100
dans la carte triée. Code qui fonctionne avec les nombres:new Map([...map.entries()].sort((e1, e2) => e1[0] - e2[0]))
Réponse courte
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 ))
Par exemple, en comparant des chaînes de valeurs, qui peuvent être égales, nous transmettons une fonction de tri qui accède à [1] et a une condition d'égalité qui renvoie 0:
new Map([...map].sort((a, b) => (a[1] > b[1] && 1) || (a[1] === b[1] ? 0 : -1)))
En comparant des chaînes de clé, qui ne peuvent pas être égales (des clés de chaîne identiques se remplaceraient), nous pouvons ignorer la condition d'égalité. Cependant, nous devrions toujours retourner explicitement -1, car le retour d'un paresseux
a[0] > b[0]
donne incorrectement false (traité comme 0, c'est-à-dire égal) lorsquea[0] < b[0]
:new Map([...map].sort((a, b) => a[0] > b[0] ? 1 : -1))
En détail avec des exemples
Le
.entries()
dans[...map.entries()]
(suggéré dans de nombreuses réponses) est redondant, ajoutant probablement une itération supplémentaire de la carte à moins que le moteur JS ne l'optimise pour vous.Dans le cas de test simple, vous pouvez faire ce que la question demande avec:
new Map([...map].sort())
... qui, si les clés sont toutes des chaînes, compare les chaînes de valeur-clé jointes par des virgules écrasées et forcées comme
'2-1,foo'
et'0-1,[object Object]'
, en renvoyant une nouvelle carte avec le nouvel ordre d'insertion:Remarque: si vous ne voyez que
{}
dans la sortie de la console de SO, regardez dans la console de votre navigateur réelconst map = new Map([ ['2-1', 'foo'], ['0-1', { bar: 'bar' }], ['3-5', () => 'fuz'], ['3-2', [ 'baz' ]] ]) console.log(new Map([...map].sort()))
CEPENDANT , ce n'est pas une bonne pratique de s'appuyer sur la coercition et la stringification comme celle-ci. Vous pouvez avoir des surprises comme:
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()) }
Des bogues comme celui-ci sont vraiment difficiles à déboguer - ne le risquez pas!
Si vous souhaitez trier sur des clés ou des valeurs, il est préférable d'y accéder explicitement avec
a[0]
etb[0]
dans la fonction de tri, comme ceci. Notez que nous devrions retourner-1
et1
pour avant et après, pasfalse
ou0
comme avec rawa[0] > b[0]
car cela est traité comme égal: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)))
la source
Convertir
Map
en un tableau en utilisantArray.from
, trier un tableau, reconvertir enMap
, par exemplenew Map( Array .from(eventsByDate) .sort((a, b) => { // a[0], b[0] is the key of the map return a[0] - b[0]; }) )
la source
[...map.values()].sort()
n'a pas fonctionné pour moi, mais aArray.from(map.values()).sort()
faitL'idée est d'extraire les clés de votre carte dans un tableau. Triez ce tableau. Ensuite, parcourez ce tableau trié, obtenez sa paire de valeurs à partir de la carte non triée et placez-les dans une nouvelle carte. La nouvelle carte sera triée. Le code ci-dessous est sa mise en œuvre:
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);
la source
unsortedMap.keys()
. Devrait également l'keys.sort().map...
êtrekeys.sort().forEach...
.Vous pouvez convertir en un tableau et y appeler des méthodes de recherche de tableau:
[...map].sort(/* etc */);
la source
Malheureusement, pas vraiment implémenté dans ES6. Vous avez cette fonctionnalité avec OrderedMap.sort () d' ImmutableJS ou _.sortBy () de Lodash.
la source
Une façon est d'obtenir le tableau d'entrées, de le trier, puis de créer une nouvelle carte avec le tableau trié:
let ar = [...myMap.entries()]; sortedArray = ar.sort(); sortedMap = new Map(sortedArray);
Mais si vous ne voulez pas créer un nouvel objet, mais travailler sur le même, vous pouvez faire quelque chose comme ceci:
// 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); })
la source
L'extrait ci-dessous trie la carte donnée par ses clés et mappe à nouveau les clés sur des objets clé-valeur. J'ai utilisé la fonction localeCompare car ma carte était une carte d'objet string-> string.
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; });
résultat:
[{t:'tt'}, {x:'xx'}, {y: 'yy'}];
la source
D'après ce que je vois, il n'est actuellement pas possible de trier correctement une carte.
Les autres solutions où la carte est convertie en un tableau et triée de cette façon ont le bogue suivant:
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}
Le tri crée un nouvel objet et tous les autres pointeurs vers l'objet non trié sont cassés.
la source
2 heures passées à entrer dans les détails.
Notez que la réponse à la question est déjà donnée à https://stackoverflow.com/a/31159284/984471
Cependant, la question a des touches qui ne sont pas habituelles,
un exemple clair et général avec l' explication, est ci - dessous qui fournit un peu plus de clarté:
.
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
J'espère que ça t'as aidé.
la source
Peut-être un exemple plus réaliste de ne pas trier un objet Map, mais de préparer le tri avant de faire la Map. La syntaxe devient en fait assez compacte si vous le faites comme ça. Vous pouvez appliquer le tri avant la fonction de carte comme ceci, avec une fonction de tri avant la carte (exemple d'une application React sur laquelle je travaille en utilisant la syntaxe JSX)
Notez que je définis ici une fonction de tri à l'intérieur en utilisant une fonction de flèche qui renvoie -1 si elle est plus petite et 0 sinon triée sur une propriété des objets Javascript dans le tableau que j'obtiens d'une 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> )
la source
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"}
la source