Можно ли отсортировать записи объекта карты es6?
var map = new Map();
map.set('2-1', foo);
map.set('0-1', bar);
приводит к:
map.entries = {
0: {"2-1", foo },
1: {"0-1", bar }
}
Можно ли отсортировать записи по их ключам?
map.entries = {
0: {"0-1", bar },
1: {"2-1", foo }
}
javascript
ecmascript-6
Иван Бахер
источник
источник
Ответы:
Согласно документации MDN:
Вы можете сделать это так:
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)
Используя
.sort()
, помните, что массив сортируется в соответствии со значением кодовой точки Unicode каждого символа, в соответствии с преобразованием строки каждого элемента. Так2-1, 0-1, 3-1
будет отсортировано правильно.источник
var mapAsc = new Map([...map.entries()].sort((a,b) => a[0] > b[0]));
используя стрелочную функцию (лямбда)2-1,foo
с0-1,bar
и3-1,baz
(a,b) => a[0] > b[0]
!...
точки имеют большое значение в противном случае вы пытаетесь сортировать MapIterator1e-9
, после100
на отсортированной карте. Код, работающий с числами:new Map([...map.entries()].sort((e1, e2) => e1[0] - e2[0]))
Короткий ответ
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 ))
Например, сравнивая строки значений, которые могут быть равными, мы передаем функцию сортировки, которая обращается к [1] и имеет условие равенства, которое возвращает 0:
new Map([...map].sort((a, b) => (a[1] > b[1] && 1) || (a[1] === b[1] ? 0 : -1)))
Сравнивая ключевые строки, которые не могут быть равными (одинаковые строковые ключи будут перезаписывать друг друга), мы можем пропустить условие равенства. Однако мы все равно должны явно возвращать -1, потому что возвращение ленивого запроса
a[0] > b[0]
неверно дает false (обрабатывается как 0, т.е. равно), когдаa[0] < b[0]
:new Map([...map].sort((a, b) => a[0] > b[0] ? 1 : -1))
Подробно с примерами
.entries()
В[...map.entries()]
(предлагается во многих ответах) является излишним, возможно добавление дополнительной итерации карты , если Оптимизирует двигателя JS , что далеко для вас.В простом тестовом примере вы можете сделать то, что требует вопрос, с помощью:
new Map([...map].sort())
... который, если все ключи являются строками, сравнивает сжатые и принудительно соединенные запятыми строки ключ-значение, такие как
'2-1,foo'
и'0-1,[object Object]'
, возвращая новую карту с новым порядком вставки:Примечание: если вы видите только
{}
вывод консоли SO, посмотрите в консоль своего реального браузера.const map = new Map([ ['2-1', 'foo'], ['0-1', { bar: 'bar' }], ['3-5', () => 'fuz'], ['3-2', [ 'baz' ]] ]) console.log(new Map([...map].sort()))
ОДНАКО , полагаться на такое принуждение и привязку - не лучшая практика. Вы можете получить такие сюрпризы, как:
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()) }
Подобные ошибки действительно сложно отлаживать - не рискуйте!
Если вы хотите отсортировать ключи или значения, лучше всего обращаться к ним явно с помощью функции сортировки
a[0]
иb[0]
в ней, например. Обратите внимание, что мы должны возвращать-1
and1
for before и after, notfalse
или0
as с raw,a[0] > b[0]
потому что это рассматривается как равное: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)))
источник
Преобразовать
Map
в массив с помощьюArray.from
, отсортировать массив, преобразовать обратноMap
, напримерnew Map( Array .from(eventsByDate) .sort((a, b) => { // a[0], b[0] is the key of the map return a[0] - b[0]; }) )
источник
[...map.values()].sort()
не работает для меня, ноArray.from(map.values()).sort()
сделалИдея состоит в том, чтобы извлечь ключи вашей карты в массив. Отсортируйте этот массив. Затем выполните итерацию по этому отсортированному массиву, получите его пару значений из несортированной карты и поместите их в новую карту. Новая карта будет отсортирована. Код ниже - это его реализация:
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);
источник
unsortedMap.keys()
. Тожеkeys.sort().map...
должно бытьkeys.sort().forEach...
.Вы можете преобразовать его в массив и вызвать для него методы сортировки массива:
[...map].sort(/* etc */);
источник
К сожалению, на самом деле не реализовано в ES6. У вас есть эта функция с помощью OrderedMap.sort () из ImmutableJS или _.sortBy () из Lodash.
источник
Один из способов - получить массив записей, отсортировать его, а затем создать новую карту с отсортированным массивом:
let ar = [...myMap.entries()]; sortedArray = ar.sort(); sortedMap = new Map(sortedArray);
Но если вы не хотите создавать новый объект, а работать с ним, вы можете сделать что-то вроде этого:
// 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); })
источник
Приведенный ниже фрагмент сортирует данную карту по ее ключам и снова сопоставляет ключи с объектами "ключ-значение". Я использовал функцию localeCompare, так как моя карта была строковой-> строковой объектной картой.
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; });
результат:
[{t:'tt'}, {x:'xx'}, {y: 'yy'}];
источник
Насколько я понимаю, в настоящее время невозможно правильно отсортировать карту.
В других решениях, где карта преобразуется в массив и сортируется таким образом, есть следующая ошибка:
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}
Сортировка создает новый объект, а все остальные указатели на несортированный объект перестают работать.
источник
На вникание в детали ушло 2 часа.
Обратите внимание, что ответ на вопрос уже дан на https://stackoverflow.com/a/31159284/984471.
Однако в этом вопросе есть ключи, которые не являются обычными.
Ниже приведен ясный и общий пример с объяснением, который обеспечивает дополнительную ясность:
.
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
Надеюсь, это поможет.
источник
Возможно, это более реалистичный пример того, как не сортировать объект Map, а подготовить сортировку перед выполнением Map. Если вы сделаете это так, синтаксис станет довольно компактным. Вы можете применить сортировку перед функцией карты, подобной этой, с функцией сортировки перед картой (пример из приложения React, над которым я работаю с использованием синтаксиса JSX)
Отметьте, что здесь я определяю функцию сортировки внутри, используя функцию стрелки, которая возвращает -1, если она меньше, и 0, в противном случае сортируется по свойству объектов Javascript в массиве, который я получаю от 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> )
источник
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"}
источник