如何在JavaScript中按值对映射进行排序?

84

如何按值对此映射进行排序?

var map = new Map();
map.set('orange', 10);
map.set('apple', 5);
map.set('banana', 20);
map.set('cherry', 13);

5
Map是一种数据结构,不应该被排序。它存储键值对,对哈希表进行排序没有太多意义。如果需要排序,可以将其转换为数组,然后对数组进行排序。 - Yeldar Kurmangaliyev
我同意你不应该依赖于Map的排序。 - Mulan
可能是在JavaScript中按值对字典进行排序的重复问题。 - Thilo
使用普通对象而不是映射来存储按字母顺序排序的键值对。 - dandavis
Map对象保存键值对并记住键的原始插入顺序。https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map - Denis Giffeler
10个回答

162
const myMap = new Map();
myMap.set("a",3);
myMap.set("c",4);
myMap.set("b",1);
myMap.set("d",2);

// sort by value
const mapSort1 = new Map([...myMap.entries()].sort((a, b) => b[1] - a[1]));
console.log(mapSort1);
// Map(4) {"c" => 4, "a" => 3, "d" => 2, "b" => 1}

const mapSort2 = new Map([...myMap.entries()].sort((a, b) => a[1] - b[1]));
console.log(mapSort2);
// Map(4) {"b" => 1, "d" => 2, "a" => 3, "c" => 4}

// sort by key
const mapSort3 = new Map([...myMap.entries()].sort());
console.log(mapSort3);
// Map(4) {"a" => 3, "b" => 1, "c" => 4, "d" => 2}

const mapSort4 = new Map([...myMap.entries()].reverse());
console.log(mapSort4);
// Map(4) {"d" => 2, "b" => 1, "c" => 4, "a" => 3}

1
谢谢!你的方法非常干净。不过,你能解释一下new Map([...myMap.entries()])吗?这种方法在Internet Explorer上兼容吗? - Maxbester
似乎在IE中无法使用数组展开运算符。 - Ian Kim
是的,这就是我想的。有没有什么干净的方法可以在IE上运行? - Maxbester

51
你可以采用不同的方法,通过更改 Symbol.iteratorMap.prototype[@@iterator]() 来得到自定义排序的结果。

var map = new Map();

map.set("orange", 10);
map.set("apple", 5);
map.set("banana", 20);
map.set("cherry", 13);

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

for (let [key, value] of map) {     // get data sorted
    console.log(key + ' ' + value);
}

console.log([...map]);              // sorted order
console.log([...map.entries()]);    // original insertation order
.as-console-wrapper { max-height: 100% !important; top: 0; }


1
我认为这很酷,但应该非常小心地使用,以免对已排序的列表进行排序。 - DanG
事实上,我认为添加一个“isSorted”属性会很好,如果是这样,就不要排序。可以进一步添加一个[Symbol.set]生成器用于二进制插入,以及一个[Symbol.get]用于基于isSorted标志的二进制搜索分支。但我担心这种方法的长期安全性。我认为间接引用可能更为谨慎。 - DanG

10
您可以缩短函数并在ES6中使用箭头函数(lambda)来实现。
 let m2= new Map([...m.entries()].sort((a,b) => b[1] - a[1]))

6
在ES6中,你可以这样做:(假设你的Map对象是m)。
[...m].map(e =>{ return e[1];}).slice().sort(function(a, b) {
  return a - b; 
});

扩展运算符将Map对象转换为数组,然后取出每个子数组的第二个元素以构建新数组,再对其进行排序。如果想按降序排序,只需用b - a替换a - b即可。

5
你可以使用列表映射而不仅仅是映射。 试一下这个:
var yourListMaps = [];
var a = {quantity: 10, otherAttr: 'tmp1'};
var b = {quantity: 20, otherAttr: 'tmp2'};
var c = {quantity: 30, otherAttr: 'tmp3'};
yourListMaps.push(a);
yourListMaps.push(b);
yourListMaps.push(c);

如果您想按数量排序,可以执行以下操作:

// Sort c > b > a
yourListMaps.sort(function(a,b){
    return b.quantity - a.quantity;
});

或者
// Sort a > b > c
yourListMaps.sort(function(a,b){
    return a.quantity - b.quantity;
});

1
这个不起作用。我只能按照插入顺序得到结果。 - mrtechmaker
现在重新尝试一下?我觉得你复制或输入的内容有误吗? - Nguyễn Thắng

3
为了对地图对象进行排序,请使用以下代码。
const map = new Map();
map.set("key","value");
map.set("key","value");

const object = Object.keys(map.sort().reduce((a,b) => (a[k] = map[a], b), {});

console.log(object);

//This will work to sort a map by key.

0

我也想按值对Map进行排序,但我的键是数字,而值是字符串(Map<number, string>),并希望使用TypeScript来完成。

这是对我有用的方法,使用localeCompare

let json = [
    {
        "key": 2952,
        "value": "Sample Text"
    },
    {
        "key": 2961,
        "value": "Sample Text 1"
    },
    {
        "key": 2962,
        "value": "1Sample Text"
    },
    {
        "key": 2987,
        "value": "3Sample Text"
    },
    {
        "key": 2988,
        "value": "#Sample Text"
    },
    {
        "key": 4585,
        "value": "Ö Sample Text"
    },
    {
        "key": 4594,
        "value": "@Sample Text"
    }
]

let myMap = new Map(Object.entries(json));

myMap = new Map([...myMap.entries()].sort((a, b) => a[1].value.localeCompare(b[1].value)));

myMap.forEach((x) => {
    console.log(x.value)
})

0

这里有几个有效的答案,但我认为“有序映射”方面会使事情变得复杂和混乱。

假设只需要按值排序的映射中的键列表,而不是按值排序的映射条目,则可以使用以下代码:

var map = {
  orange: 10,
  apple: 5,
  banana: 20,
  cherry: 13
}

var sorted_keys = Object.keys(map).sort(function(a,b) { return map[a] - map[b]; });

这将产生:

["apple", "orange", "cherry", "banana"]

如果您想要遍历映射条目,这种方法会稍微不够优雅(现在您需要遍历已排序键的数组并获取值)但是:

  1. 这个逻辑更容易被我的简单思维所理解和记住。

  2. “按值对该地图进行排序”的最常见用例是实际上希望获得排序后的键列表:使用地图来保持计数。(例如,使用地图迭代文件中的单词,以地图记录每个单词出现的频率,然后将该地图排序以按频率获取单词列表。)

对于映射中的值不一定为数字的一般情况,请将比较器函数(传递给 Object.keys(map).sort 的函数)替换为类似以下内容的内容:

function(a, b) {
  return (a < b) ? -1 : ( (a > b) ? 1 : 0 );
}

(这本质上是:

function(a, b) {
  if (a < b) {
    return -1;
  } else if (a > b) {
    return 1;
  } else {
    return 0;
  }
}

但要注意,JavaScript的<>运算符在处理混合类型时有时会有一些反直觉的行为,因此根据您的映射中的值,您可能需要在比较器中包含显式类型转换逻辑。

但是请记住,使用三元(? :)运算符可以使代码更简洁。


-1
let map = new Map();
map.set("apple", 1);
map.set("banana", 5);
map.set("mango", 4);
map.set("orange", 9);

let sorted = Object.keys(map).sort((a,b) => {
    return map[b] - map[a];
});

console.log(sorted);

-1

要对对象进行排序,只需使用

const sortedObject = mapObject.sort((a,b)=>return b.value - a.value) 

sort() 不是 Map 类型的函数。 - PaulBunion

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接