Javascript 是否可以对 ES6 地图对象进行排序?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31158902/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it possible to sort a ES6 map object?
提问by Ivan Bacher
Is it possible to sort the entries of a es6 map object?
是否可以对 es6 地图对象的条目进行排序?
var map = new Map();
map.set('2-1', foo);
map.set('0-1', bar);
results in:
结果是:
map.entries = {
0: {"2-1", foo },
1: {"0-1", bar }
}
Is it possible to sort the entries based on their keys?
是否可以根据键对条目进行排序?
map.entries = {
0: {"0-1", bar },
1: {"2-1", foo }
}
回答by Walter Chapilliquen - wZVanG
According MDN documentation:
根据 MDN 文档:
A Map object iterates its elements in insertion order.
Map 对象按插入顺序迭代其元素。
You could do it this way:
你可以这样做:
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)
Using .sort()
, remember that the array is sorted according to each character's Unicode code point value, according to the string conversion of each element. So 2-1, 0-1, 3-1
will be sorted correctly.
使用 时.sort()
,请记住数组是根据每个字符的 Unicode 代码点值排序的,根据每个元素的字符串转换。所以2-1, 0-1, 3-1
会被正确排序。
回答by user56reinstatemonica8
Short answer
简答
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
))
For example, comparing value strings, which can be equal, we pass a sort function that accesses [1] and has an equals condition that returns 0:
例如,比较可以相等的值字符串,我们传递一个访问 [1] 并具有返回 0 的相等条件的排序函数:
new Map([...map].sort((a, b) => (a[1] > b[1] && 1) || (a[1] === b[1] ? 0 : -1)))
Comparing key strings, which can't be equal (identical string keys would overwrite each other), we can skip the equals condition. However, we should still explicitly return -1, because returning a lazy a[0] > b[0]
incorrectly gives false (treated as 0, i.e. equals) when a[0] < b[0]
:
比较不能相等的键字符串(相同的字符串键会相互覆盖),我们可以跳过相等条件。但是,我们仍然应该显式返回 -1,因为在以下情况下返回一个 lazy 会a[0] > b[0]
错误地给出 false(视为 0,即等于)a[0] < b[0]
:
new Map([...map].sort((a, b) => a[0] > b[0] ? 1 : -1))
In detail with examples
用例子详细说明
The .entries()
in [...map.entries()]
(suggested in many answers) is redundant, probably adding an extra iteration of the map unless the JS engine optimises that away for you.
将.entries()
在[...map.entries()]
(在许多答案的建议)是多余的,可能是添加地图,除非JS引擎优化了离开你额外的迭代。
In the simple test case, you can do what the question asks for with:
在简单的测试用例中,您可以执行问题的要求:
new Map([...map].sort())
...which, if the keys are all strings, compares squashed and coerced comma-joined key-value strings like '2-1,foo'
and '0-1,[object Object]'
, returning a new Map with the new insertion order:
...其中,如果键都是字符串,则比较压缩和强制逗号连接的键值字符串,如'2-1,foo'
and '0-1,[object Object]'
,返回具有新插入顺序的新 Map:
Note: if you see only {}
in SO's console output, look in your real browser console
注意:如果您只{}
在 SO 的控制台输出中看到,请查看您的真实浏览器控制台
const map = new Map([
['2-1', 'foo'],
['0-1', { bar: 'bar' }],
['3-5', () => 'fuz'],
['3-2', [ 'baz' ]]
])
console.log(new Map([...map].sort()))
HOWEVER, it's not a good practice to rely on coercion and stringification like this. You can get surprises like:
然而,像这样依赖强制和字符串化并不是一个好习惯。您可以获得以下惊喜:
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())
}
Bugs like this are really hard to debug - don't risk it!
像这样的错误真的很难调试 - 不要冒险!
If you want to sort on keys or values, it's best to access them explicitly with a[0]
and b[0]
in the sort function, like this. Note that we should return -1
and 1
for before and after, not false
or 0
as with raw a[0] > b[0]
because that is treated as equals:
如果要对键或值进行排序,最好使用a[0]
和b[0]
在排序函数中显式访问它们,如下所示。请注意,我们应该 return -1
and 1
for before 和 after,而不是false
or 0
as with rawa[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)))
回答by Gajus
Convert Map
to an array using Array.from
, sort array, convert back to Map
, e.g.
转换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];
})
)
回答by Mikematic
The idea is to extract the keys of your map into an array. Sort this array. Then iterate over this sorted array, get its value pair from the unsorted map and put them into a new map. The new map will be in sorted order. The code below is it's implementation:
这个想法是将地图的键提取到一个数组中。对这个数组进行排序。然后迭代这个已排序的数组,从未排序的映射中获取它的值对并将它们放入一个新的映射中。新地图将按排序顺序排列。下面的代码是它的实现:
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);
回答by Moshe Estroti
One way is to get the entries array, sort it, and then create a new Map with the sorted array:
一种方法是获取条目数组,对其进行排序,然后使用排序后的数组创建一个新的 Map:
let ar = [...myMap.entries()];
sortedArray = ar.sort();
sortedMap = new Map(sortedArray);
But if you don't want to create a new object, but to work on the same one, you can do something like this:
但是,如果您不想创建新对象,而是要处理同一个对象,则可以执行以下操作:
// 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);
})
回答by wesbos
You can convert to an array and call array soring methods on it:
您可以转换为数组并对其调用数组排序方法:
[...map].sort(/* etc */);
回答by devside
Unfortunately, not really implemented in ES6. You have this feature with OrderedMap.sort()from ImmutableJS or _.sortBy()from Lodash.
不幸的是,在 ES6 中并没有真正实现。你有这个功能OrderedMap.sort()从ImmutableJS或_.sortBy()从Lodash。
回答by Abdullah Gürsu
The snippet below sorts given map by its keys and maps the keys to key-value objects again. I used localeCompare function since my map was string->string object map.
下面的代码段按其键对给定的映射进行排序,并将键再次映射到键值对象。我使用 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;
});
result: [{t:'tt'}, {x:'xx'}, {y: 'yy'}];
结果: [{t:'tt'}, {x:'xx'}, {y: 'yy'}];
回答by Lacho Tomov
As far as I see it's currently not possible to sort a Map properly.
据我所知,目前无法正确排序地图。
The other solutions where the Map is converted into an array and sorted this way have the following bug:
将 Map 转换为数组并以这种方式排序的其他解决方案具有以下错误:
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}
The sorting creates a new object and all other pointers to the unsorted object get broken.
排序会创建一个新对象,而指向未排序对象的所有其他指针都会被破坏。
回答by Manohar Reddy Poreddy
2 hours spent to get into details.
花了2个小时来了解细节。
Note that the answer for question is already given at https://stackoverflow.com/a/31159284/984471
请注意,问题的答案已在https://stackoverflow.com/a/31159284/984471 中给出
However, the question has keys that are not usual ones,
A clear & general example with explanation, is belowthat provides some more clarity:
然而,这个问题的关键是不常见的,下面是
一个带有解释的清晰和通用的例子,它提供了一些更清晰的信息:
- Some more examples here: https://javascript.info/map-set
- You can copy-paste the below code to following link, and modify it for your specific use case: https://www.jdoodle.com/execute-nodejs-online/
- 这里还有一些例子:https: //javascript.info/map-set
- 您可以将以下代码复制粘贴到以下链接,并针对您的特定用例进行修改:https: //www.jdoodle.com/execute-nodejs-online/
.
.
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
Hope that helps.
希望有帮助。