是否可以对ES6地图对象进行排序?

Iva*_*her 59 javascript ecmascript-6

是否可以对es6地图对象的条目进行排序?

var map = new Map();
map.set('2-1', foo);
map.set('0-1', bar);
Run Code Online (Sandbox Code Playgroud)

结果是:

map.entries = {
    0: {"2-1", foo },
    1: {"0-1", bar }
}
Run Code Online (Sandbox Code Playgroud)

是否可以根据键输入条目?

map.entries = {
    0: {"0-1", bar },
    1: {"2-1", foo }
}
Run Code Online (Sandbox Code Playgroud)

Wal*_*anG 97

根据MDN文件:

Map对象按插入顺序迭代其元素.

你可以这样做:

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)
Run Code Online (Sandbox Code Playgroud)

使用时.sort(),请记住,根据每个元素的字符串转换,数组根据每个字符的Unicode代码点值进行排序.所以2-1, 0-1, 3-1将正确排序.

  • @JimmyChandra:[不要使用`(a,b)=> a [0]> b [0]`!](http://stackoverflow.com/q/24080785/1048572) (10认同)
  • 你可以将这个函数(a,b)缩短为:`var mapAsc = new Map([... map.entries()].sort((a,b)=> a [0]> b [0]) );`使用箭头函数(lambda) (5认同)
  • 实际上,它严格按照词法将“ 2-1,foo”与“ 0-1,bar”和“ 3-1,baz”进行比较。 (2认同)
  • `...`点很重要,否则你试图对MapIterator进行排序 (2认同)
  • 如果地图键是数字,您将得到无效的结果,在排序地图中,诸如“1e-9”之类的数字放在“100”之后。处理数字的代码:`new Map([...map.entries()].sort((e1, e2) => e1[0] - e2[0]))` (2认同)

Gaj*_*jus 24

转换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];
    })
)
Run Code Online (Sandbox Code Playgroud)

  • 这实际上对我有帮助,没有 Array.from,Typescript 给了我一个编译错误。 (3认同)

use*_*ca8 18

简短的回答

 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
 ))
Run Code Online (Sandbox Code Playgroud)

例如,比较可以相等的值字符串,我们传递一个访问[1]并具有返回0的等于条件的sort函数:

 new Map([...map].sort((a, b) => (a[1] > b[1] && 1) || a[1] === b[1] ? 0 : -1))
Run Code Online (Sandbox Code Playgroud)

比较关键字符串,它们不能相等(相同的字符串键会相互覆盖),我们可以跳过equals条件.但是,我们仍应显式返回-1,因为在以下情况下,返回惰性a[0] > b[0]错误会给出false(视为0,即等于)a[0] < b[0]:

 new Map([...map].sort((a, b) => a[0] > b[0] ? 1 : -1))
Run Code Online (Sandbox Code Playgroud)

详细举例说明

.entries()[...map.entries()](在许多答案的建议)是多余的,除非JS引擎优化是离开你可能添加在地图的一个额外的迭代.

在简单的测试用例中,您可以执行以下问题:

new Map([...map].sort())
Run Code Online (Sandbox Code Playgroud)

...如果键都是字符串,则比较压缩和强制逗号连接的键值字符串,比如'2-1,foo''0-1,[object Object]',返回带有新插入顺序的新Map:

注意:如果只看到{}SO的控制台输出,请查看真实的浏览器控制台

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

console.log(new Map([...map].sort()))
Run Code Online (Sandbox Code Playgroud)

但是,依靠像这样的强制和字符串化并不是一个好习惯.您可以获得以下惊喜:

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())
}
Run Code Online (Sandbox Code Playgroud)

像这样的错误很难调试 - 不要冒险!

如果要对键或值进行排序,最好使用a[0]b[0]在sort函数中显式访问它们,如下所示.请注意,我们应该返回-11之前和之后,不是false0与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)))
Run Code Online (Sandbox Code Playgroud)

  • 什么答案,我们必须修复SO发现机制.这件好事不应该在这里消失. (5认同)

小智 8

我们的想法是将地图的键提取到数组中.对此数组进行排序 然后遍历此排序数组,从未排序的映射中获取其值对并将它们放入新映射中.新地图将按排序顺序排列.下面的代码是它的实现:

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);
Run Code Online (Sandbox Code Playgroud)

  • 可以使用`unsortedMap.keys()`简单地确定未排序的键.另外`keys.sort().map ...`应该是`keys.sort().forEach ...`. (2认同)

小智 8

我建议为您的地图对象使用自定义迭代器来实现排序访问,如下所示:

map[Symbol.iterator] = function* () {
    yield* [...map.entries()].sort((a, b) => a[0].localeCompare(b[0]));
}
Run Code Online (Sandbox Code Playgroud)

使用迭代器的优点是它只需声明一次。在映射中添加/删除条目后,映射上的新 for 循环将使用迭代器自动反映此更改。上述大多数答案中所示的排序副本不会,因为它们仅反映地图在某一时间点的状态。

这是使用您的初始情况的完整工作示例。

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

for (let [key, val] of map) {
    console.log(key + ' - ' + val.name);
}
// 2-1 - foo
// 1-0 - bar

map[Symbol.iterator] = function* () {
    yield* [...map.entries()].sort((a, b) => a[0].localeCompare(b[0]));
}

for (let [key, val] of map) {
    console.log(key + ' - ' + val.name);
}
// 1-0 - bar
// 2-1 - foo

map.set('2-0', { name: 'zzz' });

for (let [key, val] of map) {
    console.log(key + ' - ' + val.name);
}
// 1-0 - bar
// 2-0 - zzz
// 2-1 - foo
Run Code Online (Sandbox Code Playgroud)

问候。


wes*_*bos 6

您可以转换为数组并对其调用数组排序方法:

[...map].sort(/* etc */);
Run Code Online (Sandbox Code Playgroud)

  • 然后你丢了钥匙 (5认同)
  • 什么?你得到一个数组而不是地图或对象 (3认同)