How to sort a map by value in JavaScript? [SOLVED]


NodeJS

Is it possible to sort a map using values in JS?

People can easily comprehend data when there is a pattern or order to it, and one of the easiest ones is the ascending, descending, or alphabetical order of data. It’s easier to monitor or use a series of numbers (e.g statistics) when they ascend or descend (1 to 10 or 10 to 1), or a series of words when they are alphabetical (a to Z or Z to a).

To achieve this necessary state, the sort operation is important, and within JavaScript (JS), there are methods that help us to achieve this sort operation. However, it can be a little complex when you have a key-value pair relationship (such as objects, maps, etc.) between values and need to sort by the value side.

In this article, we will understand how to sort a map by its value in JS in ascending or descending order when it comes to number and string values.

 

What are Maps?

The key-value pair structure

There are different data structures that programming languages like JS support, and are helpful when we design algorithms for our applications. Some data structures make use of key-value relationships between different data types. Primitive data types such as String, Number, Boolean, and Symbol are often used as either the key or value in these types of data structures giving them a lot of extensive features. One of such data structures is the popular object.

 

Objects

Objects allow us to group data values together to create relationships using the key-value relationship. Often, objects keys are called properties and have what’s called a property-value relationship. Objects, themselves, can hold other objects making for an interesting data structure.

Let’s create a simple object with the obj binding.

let obj = {
    name: "David",
    age: 34,
    relationship: "Single",
    accountActivated: false
}

console.log(obj);

Output:

{
  name: 'David',
  age: 34,
  relationship: 'Single',
  accountActivated: false
}

The properties we assign to the obj object are not the only properties it holds and can often become an issue especially when we only need the properties we assign to it.

console.log("toString" in obj)

Output:

true

All the properties we assigned are simply enumerable, and the other properties are non-enumerable. The non-enumerable properties are obtained from the Object.prototype which is used to create the object itself. The output above occurs because there is a toString method that is inherited from Object.prototype.

To have none of the properties from the Object.prototype, we can make use of the data structure called Map.

 

Maps

Maps are data structures that have key-value relationships or associations where the keys and values can be of any data type (unlike objects where the key has to be a Symbol or String). With Maps, only the key and values we assign are present within it.

let map = new Map();

map.set("1-1", "foo");
map.set("0-1", "bar");
map.set("2-1", "baff");

console.log(map)

Output:

Map(3) { '1-1' => 'foo', '0-1' => 'bar', '2-1' => 'baff' }

The new Map() creates the empty Map, and the set() function insert new key-value relationship. We can check the same toString value within the map binding we created.

console.log(map.has("toString"));

Output:

false

 

How to sort maps by key

To sort a map, we need a sort function. Though the map data structure doesn’t have its own, objects(arrays or generally iterable) have a sort function we can make use of. Let’s experiment with a simple object

let arr = [2, 3, 0, 9, 5, 2]
console.log(arr.sort());

Output:

[ 0, 2, 2, 3, 5, 9 ]

Now, we need a way to convert a Map to an iterable that we can sort, and there is a method for that, entries(). The method returns an iterable of key, value pairs for every entry in the map.

let fruit = new Map();

fruit.set("orange", 12);
fruit.set("apple", 30);
fruit.set("banana", 20);
fruit.set("tangerine", 13);

console.log(fruit.entries())

Output:

[Map Entries] {
  [ 'orange', 12 ],
  [ 'apple', 30 ],
  [ 'banana', 20 ],
  [ 'tangerine', 13 ]
}

Now, we have an iterator object within contains arrays of the key and value at position 0 and 1 respectively for each array.

With this iterator object, we create a new array using the spread operator, ... resulting in an array of arrays - [...fruit.entries()]. On this array, we can apply the sort() method. The sort() method uses the first value of the inner array to sort the array of arrays.

console.log([...fruit.entries()].sort());

Output:

[
  [ 'apple', 30 ],
  [ 'banana', 20 ],
  [ 'orange', 12 ],
  [ 'tangerine', 13 ]
]

Using this sorted array, we can create a new Map using the new Map() expression

let sortedFruit = new Map([...fruit.entries()].sort());
console.log(sortedFruit);

Output:

Map(4) {
  'apple' => 30,
  'banana' => 20,
  'orange' => 12,
  'tangerine' => 13
}

 

Different methods to sort maps by value

Now, let’s get to the crux of the matter. In the previous section, we sorted the map using just the key value which is the first value (position 0) within the array of the Map Entries. Here, we will map sort by value in JS using two methods depending on the data type of the values we have.

All the previous logic and code apply but with some addition to the sort() expression. Previously, we didn’t pass any argument to the sort function. To sort the value part of the key-value pair, we will need to pass an anonymous function. Depending on the data type of the value, we can use different functions

 

Method 1: Sort By String Values

For String values, we can use the localeCompare, which determines whether two strings are equivalent in the current or specified locale. If the reference string is lexicographically greater than the compare string, localCompare returns a positive number, and if the opposite, it returns a negative number. However, if both strings are equivalent, it returns 0.

console.log("b".localeCompare("a"));
console.log("a".localeCompare("Z"));

Output:

1
-1

So, with this function, we can use the anonymous function to compare the values.

Remember, when we use the map.entries() method, we get an iterator object with arrays representing each Map entry. There are two values within each array (e.g [ 'apple', 30 ]) with the first value representing the key, and the second value representing the value. Therefore, the value will have a positional value of 1 within the array.

Let’s create a Map with string values.

let map = new Map();

map.set("1-1", "foo");
map.set("0-1", "bar");
map.set("2-1", "baff");
map.set("3-1", "bafx");

console.log(map);

Output:

Map(4) {
  '1-1' => 'foo',
  '0-1' => 'bar',
  '2-1' => 'baff',
  '3-1' => 'bafx'
}

Now, let’s sort using the logic we have described

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

console.log(sortedMapValues);

Output:

Map(4) {
  '2-1' => 'baff',
  '3-1' => 'bafx',
  '0-1' => 'bar',
  '1-1' => 'foo'
}

Everything is sorted alphabetically from a - z. To start from z - a, we can switch the reference string and compared string.

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

console.log(sortedMapValues);

Output:

Map(4) {
  '1-1' => 'foo',
  '0-1' => 'bar',
  '3-1' => 'bafx',
  '2-1' => 'baff'
}

 

Method 2: Sort By Numeric Values

To sort numeric values, the simple process of subtraction helps with sorting the number where we compare the first value to the previous value, and the result of the subtraction determines its position.

Let’s use the same fruit Map.

let fruit = new Map();
fruit.set("orange", 12);
fruit.set("apple", 30);
fruit.set("banana", 20);
fruit.set("tangerine", 13);

console.log(fruit);

Output:

Map(4) {
  'orange' => 12,
  'apple' => 30,
  'banana' => 20,
  'tangerine' => 13
}

For ascending order, we will subtract the second value from the first value

let sortedFruit = new Map([...fruit.entries()].sort((a, b) => a[1] - b[1]));
console.log(sortedFruit);

Output:

Map(4) {
  'orange' => 12,
  'tangerine' => 13,
  'banana' => 20,
  'apple' => 30
}

For descending order, we will subtract the first value from the second value

let sortedFruit = new Map([...fruit.entries()].sort((a, b) => b[1] - a[1]));
console.log(sortedFruit);

Output:

Map(4) {
  'apple' => 30,
  'banana' => 20,
  'tangerine' => 13,
  'orange' => 12
}

 

Summary

To map sort by value requires us to make use of two methods, sort() and entries(), regardless of the data type values. For string values, the use of the localeCompare method helps us to sort lexicographically, and the compareFn anonymous function allows sorting numbers.

Map sort by values in JS requires iterator object and an understanding of how they operate, and how the sort() function works intricately. The further readings are good starting points.

 

Further Reading

Array.prototype.sort() - JavaScript | MDN (mozilla.org)
Map.prototype.entries() - JavaScript | MDN (mozilla.org)

 

Olorunfemi Akinlua

Olorunfemi Akinlua

He is boasting over five years of experience in JavaScript, specializing in technical content writing and UX design. With a keen focus on programming languages, he crafts compelling content and designs user-friendly interfaces to enhance digital experiences across various domains. You can connect with him on his LinkedIn profile.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment