Czy można posortować obiekt mapy ES6?

Czy możliwe jest sortowanie wpisów obiektu mapy es6?

var map = new Map();
map.set('2-1', foo);
map.set('0-1', bar);

Wyniki w:

map.entries = {
    0: {"2-1", foo },
    1: {"0-1", bar }
}

Czy możliwe jest sortowanie wpisów na podstawie ich kluczy?

map.entries = {
    0: {"0-1", bar },
    1: {"2-1", foo }
}
Author: Jason Aller, 2015-07-01

10 answers

Zgodnie z dokumentacją MDN:

Obiekt Map iteruje swoje elementy w kolejności wstawiania.

Możesz to zrobić w ten sposób:

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)

Używając .sort(), Należy pamiętać, że tablica jest sortowana według wartości punktu kodu Unicode każdego znaku, zgodnie z konwersją ciągu każdego elementu. Więc 2-1, 0-1, 3-1 będzie poprawnie posortowane.

 62
Author: Walter Chapilliquen - wZVanG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-01 11:18:53

Konwertuj Map na tablicę za pomocą Array.from, sort array, convert back to Map, np.

new Map(
  Array
    .from(eventsByDate)
    .sort((a, b) => {
      // a[0], b[0] is the key of the map
      return a[0] - b[0];
    })
)
 16
Author: Gajus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-22 09:15:30

Chodzi o wyodrębnienie kluczy z mapy do tablicy. Posortuj tę tablicę. Następnie wykonaj iterację nad tą posortowaną tablicą, Pobierz jej parę wartości z niesortowanej Mapy i umieść je na nowej mapie. Nowa mapa będzie posortowana. Poniższy kod jest jego implementacją:

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);
 6
Author: Mikematic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-16 22:50:29

Można przekonwertować do tablicy i wywołać na niej metody sortowania tablic:

[...map].sort(/* etc */);
 4
Author: wesbos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-08 19:24:28

Krótka odpowiedź

 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
 ))

Na przykład, porównując ciągi wartości, które mogą być równe, przekazujemy funkcję sortowania, która uzyskuje dostęp [1] i ma warunek równy, który zwraca 0:

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

Porównując łańcuchy kluczy, które nie mogą być równe (identyczne klucze łańcuchowe nadpisywałyby się nawzajem), możemy pominąć warunek equals. Jednak nadal powinniśmy zwracać jawnie -1, ponieważ zwracanie leniwego a[0] > b[0] niepoprawnie daje false (traktowane jako 0, tzn. równe), gdy a[0] < b[0]:

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

W szczegółach z przykładami

The .entries() in [...map.entries()] (sugerowane w wielu odpowiedziach) jest zbędny, prawdopodobnie dodając dodatkową iterację mapy, chyba że silnik JS zoptymalizuje to dla Ciebie.

W prostym przypadku testowym możesz zrobić to, o co prosi pytanie za pomocą:

new Map([...map].sort())

...które, jeśli wszystkie klucze są ciągami, porównuje zgniecione i wymuszone przecinkami łańcuchy wartości klucza, takie jak '2-1,foo' i '0-1,[object Object]', zwracając nową mapę z nowym wstawianiem kolejność:

Uwaga: Jeśli widzisz tylko {} na wyjściu konsoli SO, zajrzyj do prawdziwej konsoli przeglądarki

const map = new Map([
  ['2-1', 'foo'],
  ['0-1', { bar: 'bar' }],
  ['3-5', () => 'fuz'],
  ['3-2', [ 'baz' ]]
])

console.log(new Map([...map].sort()))

Jednak nie jest dobrą praktyką poleganie na takim przymusie i ciągnięciu. Możesz otrzymać niespodzianki takie jak:

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())
}

Takie błędy są naprawdę trudne do debugowania - nie ryzykuj!

Jeśli chcesz sortować klucze lub wartości, najlepiej uzyskać do nich jawny dostęp za pomocą a[0] i b[0] w funkcji sortowania, jak to. Zauważ, że powinniśmy zwracać -1 i 1 przed i po, a nie false lub 0 Jak z raw a[0] > b[0], ponieważ jest to traktowane jako równe:

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)))
 4
Author: user568458,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-09 12:24:10

Niestety, nie do końca zaimplementowane w ES6. Masz tę funkcję z OrderedMap.sort () from ImmutableJS or _.sortBy () z Lodash.

 1
Author: devside,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-15 12:05:14

Poniższy fragment sortuje mapę według swoich kluczy i mapuje Klucze do obiektów o wartości klucza ponownie. Użyłem funkcji localeCompare, ponieważ moja Mapa to 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;
        });

Wynik: [{t:'tt'}, {x:'xx'}, {y: 'yy'}];

 1
Author: Abdullah Gürsu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-10 22:23:43

Możesz przekształcić mapę w tablicę używając entries() metoda, posortować ją jako tablicę i utworzyć z niej nową mapę za pomocą konstuktora Mapy.

 0
Author: Vlad Zhukov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-01 10:52:43

Jednym ze sposobów jest pobranie tablicy wpisów, posortowanie jej, a następnie utworzenie nowej mapy z posortowaną tablicą:

let ar = [...myMap.entries()];
sortedArray = ar.sort();
sortedMap = new Map(sortedArray);

Ale jeśli nie chcesz tworzyć nowego obiektu, ale pracować na tym samym, możesz zrobić coś takiego:

// 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);
})
 0
Author: Moshe Estroti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-22 07:07:54
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"}
 -1
Author: Apoorva Gupta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-28 06:13:13