是否可以对 ES6 映射对象进行排序?

2022-08-30 03:00:08

是否可以对 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 }
}

答案 1

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

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


答案 2

简短的回答

 new Map([...map].sort((a, b) => 
   // Some sort function comparing keys with a[0] b[0] or values with a[1] b[1]
 ))

如果您需要字符串:正常情况下,您需要返回-1(如果较低),如果等于,则返回0;对于字符串,推荐的方法是使用.localeCompare(),它可以正确执行此操作并自动处理尴尬的字符,例如位置因用户区域设置而异的位置。.sortä

因此,下面是按字符串对映射进行排序的简单方法:

 new Map([...map].sort((a, b) => String(a[0]).localeCompare(b[0])))

...和字符串

 new Map([...map].sort((a, b) => String(a[1]).localeCompare(b[1])))

这些是类型安全的,因为它们在命中非字符串键或值时不会引发错误。开始时强制为字符串(并且有利于可读性),并且本身强制其参数为字符串而不命中错误。String()a.localeCompare()


详细举例说明

tldr: ...map.entries() 是多余的,只是...地图很好;而一个懒惰的 .sort() 而不传递排序函数,则存在由字符串强制导致的奇怪的边缘情况错误的风险。

in(在许多答案中建议)是多余的,可能会添加地图的额外迭代,除非JS引擎为您优化它。.entries()[...map.entries()]

在简单的测试用例中,您可以使用以下命令执行问题要求:

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

...如果键都是字符串,则比较压缩和强制的逗号连接键值字符串,如 和 ,返回具有新插入顺序的新 Map:'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]

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

// Examples using array destructuring. We're saying 'keys' and 'values'
// in the function names so it's clear and readable what the intent is. 
const sortStringKeys = ([a], [b]) => String(a).localeCompare(b)
const sortStringValues = ([,a], [,b]) => String(a).localeCompare(b)

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

如果您需要与字符串的字母顺序不同的比较,请不要忘记始终确保返回以及之前和之后,而不是或与原始一样,因为这被视为相等。-11false0a[0] > b[0]