Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array sorting is broken with Bigint In JS?

Tags:

javascript

It seems like Array.prototype.sort() is broken with BigInt

This works

const big = [1n, 2n, 3n, 4n];
big.sort();
console.log(big);
// expected output: Array [1n, 2n, 3n, 4n]

But this doesn't :(

const big = [1n, 2n, 3n, 4n];
big.sort((a,b)=>a-b);
console.log(big);
//Error: Cannot convert a BigInt value to a number

or am i doing something wrong?

like image 763
Laukik Avatar asked Dec 24 '20 07:12

Laukik


People also ask

Does JavaScript support BigInt?

BigInt is a built-in object in JavaScript that provides a way to represent whole numbers larger than 253-1. The largest number that JavaScript can reliably represent with the Number primitive is 253-1, which is represented by the MAX_SAFE_INTEGER constant.

Is BigInt primitive in JavaScript?

The BigInt type is a numeric primitive in JavaScript that can represent integers with arbitrary precision. With BigInts, you can safely store and operate on large integers even beyond the safe integer limit for Numbers. A BigInt is created by appending n to the end of an integer or by calling the constructor.

What does BigInt do in JavaScript?

BigInt is a new data type intended for use when integer values are larger than the range supported by the Number data type. This data type allows us to safely perform arithmetic operations on large integers, represent high-resolution timestamps, use large integer IDs, and more without the need to use a library.

What is the correct method to use in JavaScript sorting arrays?

Array.prototype.sort() The sort() method sorts the elements of an array in place and returns the reference to the same array, now sorted. The default sort order is ascending, built upon converting the elements into strings, then comparing their sequences of UTF-16 code units values.


2 Answers

JavaScript sort method requires a function as a parameter that can compare two elements of the array and return either a positive number, or a negative number or zero. Number is the keyword here.

BigInt operations like addition and subtraction returns BigInt type and not a Number type. And that's why the error you are getting.

So, Something like this should do the job

const big = [1n, 2n, 3n, 4n];
big.sort((a ,b) => {
  if(a > b) {
    return 1;
  } else if (a < b){
    return -1;
  } else {
    return 0;
  }
});
console.log(big);

Interestingly, MDN document that I linked to previously, also suggests how to sort an array of BigInts, and it is concise:

Copying the whole section here for posterity:

const mixed = [4n, 6, -12n, 10, 4, 0, 0n]
// ↪  [4n, 6, -12n, 10, 4, 0, 0n]

mixed.sort() // default sorting behavior
// ↪  [ -12n, 0, 0n, 10, 4n, 4, 6 ]

mixed.sort((a, b) => a - b)
// won't work since subtraction will not work with mixed types
// TypeError: can't convert BigInt to number

// sort with an appropriate numeric comparator
mixed.sort((a, b) => (a < b) ? -1 : ((a > b) ? 1 : 0))
// ↪  [ -12n, 0, 0n, 4n, 4, 6, 10 ]
like image 110
Nishant Avatar answered Oct 07 '22 18:10

Nishant


The reason is that a - b in the sort callback function will return a BigInt data type, while sort expects it to return something that is (or can coerce to) a Number data type.

So you can use a > b || -(a < b) as callback expression:

const big = [10n, 9n, 8n, 7n];
big.sort((a, b) => a > b || -(a < b));
console.log(big + ""); // 7,8,9,10

Note that the first version (without sort callback) does not work in general, because then sort will compare the elements as strings. It is clear that this can yield results that are not numerically sorted:

const big = [10n, 9n, 8n, 7n];
big.sort(); // string-based sort
console.log(big + ""); // 10,7,8,9 is wrong
like image 29
trincot Avatar answered Oct 07 '22 18:10

trincot