web-dev-qa-db-fra.com

Est-il possible de trier un objet de la carte ES6?

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 }
}
44
Ivan Bacher

Selon la documentation MDN:

Un objet Map itère ses éléments dans l'ordre d'insertion.

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. Donc, 2-1, 0-1, 3-1 sera trié correctement.

Convertissez Map en un tableau à l’aide de Array.from , triez un tableau, reconvertissez-le en Map, par exemple.

new Map(
  Array
    .from(eventsByDate)
    .sort((a, b) => {
      // a[0], b[0] is the key of the map
      return a[0] - b[0];
    })
)
21
Gajus

L'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 de la carte non triée et insérez-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);
7
Mikematic

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 valeur, qui peuvent être égales, nous passons une fonction de tri qui accède à [1] et possède une condition égal à qui renvoie 0:

 new Map([...map].sort((a, b) => a[1] === b[1] ? 0 : a[1] > b[1] ? 1 : -1))

En comparant les chaînes de clé, qui ne peuvent pas être égales (des chaînes de chaîne identiques se écraseraient), nous pouvons ignorer la condition égal à. Cependant, nous devrions toujours explicitement renvoyer -1, car renvoyer un a[0] > b[0] paresseux donne incorrectement false (traité comme 0, c'est-à-dire égal à égal) lorsque a[0] < b[0]:

 new Map([...map].sort((a, b) => a[0] > b[0] ? 1 : -1))

En détail avec des exemples

La .entries() in [...map.entries()] (suggérée dans de nombreuses réponses) est redondante, ce qui ajoute 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 des chaînes clé-valeur jointes par des virgules écrasées et contraintes, telles que '2-1,foo' et '0-1,[object Object]', 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éel 

const 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 contrainte et la hiérarchisation. 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())
}

Les bugs comme celui-ci sont vraiment difficiles à déboguer - ne le prenez pas!

Si vous voulez trier des clés ou des valeurs, il est préférable d'y accéder explicitement avec a[0] et b[0] dans la fonction de tri, comme ceci. Notez que nous devrions renvoyer -1 et 1 pour avant et après, et non pas false ou 0 comme avec raw a[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] ? 0 : a[1] > b[1] ? 1 : -1

console.log('By keys:', new Map([...map].sort(sortStringKeys)))
console.log('By values:', new Map([...map].sort(sortStringValues)))

6
user568458

Vous pouvez convertir en tableau et appeler des méthodes de tri sur celui-ci:

[...map].sort(/* etc */);
3
wesbos

L'extrait ci-dessous trie la carte donnée par ses clés et les associe à des objets clé-valeur. J'ai utilisé la fonction localeCompare puisque ma carte était chaîne-> chaîne objet carte.

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'}];

1
Abdullah Gürsu

Une solution consiste à obtenir le tableau d'entrées, à le trier, puis à 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 objet, 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);
})
1
Moshe Estroti

Malheureusement, pas vraiment implémenté dans ES6. Vous avez cette fonctionnalité avec OrderedMap.sort () de ImmutableJS ou _.sortBy () de Lodash. 

1
devside

Peut-être un exemple plus réaliste de ne pas trier un objet de la carte mais de préparer le tri avant de faire la carte. La syntaxe devient en fait assez compacte si vous le faites comme ceci. Vous pouvez appliquer le tri avant la fonction map comme ceci, avec une fonction de tri avant map (Exemple d'utilisation d'une application React sur laquelle je travaille à l'aide de la syntaxe JSX) 

Marquez que je définis ici une fonction de tri à l’aide d’une fonction flèche qui renvoie -1 si elle est plus petite et 0 sinon triée sur une propriété des objets Javascript du 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>
                    )
0
Tore Aurstad