83

How to sort this map by value?

var map = new Map();
map.set('orange', 10);
map.set('apple', 5);
map.set('banana', 20);
map.set('cherry', 13);
Penny Liu
  • 15,447
  • 5
  • 79
  • 98
chenxinlong
  • 1,677
  • 2
  • 15
  • 30
  • 5
    `Map` is a data structure, which is not supposed to be able to be sorted. It stores key-value pairs, and there is not much sense in sorting a hashtable. You can convert it to an array, and sort this array, if you want. – Yeldar Kurmangaliyev Jun 23 '16 at 04:42
  • I agree you should not depend on the sort of a Map – Mulan Jun 23 '16 at 04:43
  • Possible duplicate of [Sort a dictionary by value in JavaScript](http://stackoverflow.com/questions/25500316/sort-a-dictionary-by-value-in-javascript) – Thilo Jun 23 '16 at 04:45
  • use plain Objects instead of Maps to store sorted alphabetically-keyed key:value pairs. – dandavis Jun 23 '16 at 05:37
  • The Map object holds key-value pairs and remembers the original insertion order of the keys. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map – Denis Giffeler Jul 13 '22 at 07:06

10 Answers10

160
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}
Miroslav Savovski
  • 2,300
  • 2
  • 10
  • 12
  • 1
    Thanks! You method is very clean. However could you please explain the `new Map([...myMap.entries()])`. Is this method compatible with Internet Explorer? – Maxbester Jun 10 '20 at 11:31
  • [Looks like you can't use the array spread operator in IE](https://caniuse.com/#feat=mdn-javascript_operators_spread_spread_in_arrays) – Ian Kim Jul 29 '20 at 04:38
  • Yes this is what I thought. Any idea of a clean method that would work with IE? – Maxbester Sep 22 '20 at 11:44
50

Yo could take a different approach and change Symbol.iterator of Map.prototype[@@iterator]() for a custom sorted result.

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; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • 1
    I think this is cool but should be used very carefully so you're not sorting already sorted lists. – DanG Mar 17 '19 at 04:27
  • In fact I think it would be good to add an "isSorted" property, and if so then don't sort. One could go further and add a [Symbol.set] generator for binary insertion, and [Symbol.get] for binary search which forked based on the isSorted flag. I'm concerned though about the long term safety of this approach. I think indirection would likely be more prudent. – DanG Mar 17 '19 at 18:47
9

You can shorten the function and use this in ES6- using arrow function (lambda)

 let m2= new Map([...m.entries()].sort((a,b) => b[1] - a[1]))
Apoorva Ambhoj
  • 164
  • 1
  • 5
6

In ES6 you can do it like this: (assume your Map object is m).

[...m].map(e =>{ return e[1];}).slice().sort(function(a, b) {
  return a - b; 
});

the spread operator turns a Map object into an array, then takes out the second element of each subarray to build a new array, then sort it. If you want to sort in descending order just replace a - b with b - a.

newguy
  • 5,668
  • 12
  • 55
  • 95
5

You can use list maps instead of map only. Try this:

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);

And if you want to sort by quantity, you can:

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

or

// Sort a > b > c
yourListMaps.sort(function(a,b){
    return a.quantity - b.quantity;
});
Nguyễn Thắng
  • 319
  • 5
  • 14
3

To sort a map object use the below code.

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

I also wanted to sort a Map by value but my key is a number and value is a string. (Map<number, string>), and wanted to do it using TypeScript.

This is what worked for me, using 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)
})
Nishan
  • 3,644
  • 1
  • 32
  • 41
-1

To Sort Object simply use

const sortedObject = mapObject.sort((a,b)=>return b.value - a.value) 
Vicheans
  • 65
  • 1
  • 5
-1

There are several valid answers here but I think the "ordered map" aspect complicates and confuses things unnecessarily.

Assuming it is sufficient to get a list of the keys in the map sorted by value, rather than a map whose entries are sorted by value, then something like this works:

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]; });

which yields:

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

This is a little less elegant if you actually want to iterate over the map entries (now you need to iterate over the array of sorted keys and fetch the values instead) but:

  1. This logic is much easier for my simple mind to follow and to remember.

  2. There's a pretty common use case for "sort this map by value" in which you actually want the sorted list of keys: using a map to keep a tally. (E.g., iterating over the words in a file using a map to keep try of how often each word appears then sorting that map to get a list of words by frequency.)

For the general case in which the values in the map aren't necessarily numeric, replace the comparator function (the function passed to Object.keys(map).sort) with something like:

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

(which is essentially:

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

but using the ternary (? :) operator.)

But bear in mind that the behavior of JavaScript's < and > operators is sometimes a little counter-intuitive with mixed types so depending on the values in your map you may want to include explicit type-casting logic in your comparator.

Rod
  • 2,226
  • 22
  • 21
-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);