How to sort a Map in ES6 [duplicate] - javascript

This question already has answers here:
How to sort an array of integers correctly
(32 answers)
Closed 2 years ago.
I am trying to sort a map using below function
var m=new Map();
m.set('0900','0910');
m.set('1100','1200');
m.set('1000','1030');
m.set('1235','1240');
var ma=new Map([...m.entries()].sort());
console.log(ma);
Output:{ 900 => 910, 1000 => 1030, 1100 => 1200, 1235 => 1240}
the map is getting sorted, but when I use the integers instead of characters I can't able to sort it
var m=new Map();
m.set(0900,0910);
m.set(1100,1200);
m.set(1000,1030);
m.set(1235,1240);
var ma=new Map([...m.entries()].sort());
console.log(ma)
Output:
{1000 => 1030, 1100 => 1200, 1235 => 1240, 900 => 910}

sort() function, when you don't supply a compareFunction as an argument, does not really work the way you instinctively expect it to work. See the following quote from relevant MDN page:
If compareFunction is not supplied, all non-undefined array elements
are sorted by converting them to strings and comparing strings in
UTF-16 code units order. For example, "banana" comes before "cherry".
In a numeric sort, 9 comes before 80, but because numbers are
converted to strings, "80" comes before "9" in the Unicode order. All
undefined elements are sorted to the end of the array.
The numeric sort bit in the quote explains why you're getting two different sorts with strings and numbers (with "0900" and 900). To overcome this, simply provide a function to the sort to the comparisons the way you want it, like so:
let ma = new Map([...m.entries()].sort((a, z) => a[0] - z[0]);
You can look into the details of how these compareFunctions work in the same MDN page: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

Here, extract the first element with the help of destructuring out of the array and compare it.
var m=new Map();
m.set(0900,0910);
m.set(1100,1200);
m.set(1000,1030);
m.set(1235,1240);
var ma=new Map([...m.entries()].sort(([a], [b]) => a - b));
for(const e of ma) {
console.log(e);
}

MDN on Map.entries():
The entries() method returns a new Iterator object that contains the [key, value] pairs for each element in the Map object in insertion order.
When calling .sort() on the entries, it first converts the key-value pairs into strings before sorting them. That means that 0900 becomes 900, which comes after 1235, because '9' > '1' (first character of each string).
If you want to sort the entries by key, you will need to pass in a custom compareFunction argument to sort, which handles the key-value pairs and compares the keys as numbers:
var m = new Map();
m.set(0900,0910);
m.set(1100,1200);
m.set(1000,1030);
m.set(1235,1240);
var ma = new Map([...m.entries()].sort((kv1, kv2) => kv1[0] - kv2[0]));
console.log(ma);

Related

Variation: Find the object with the highest value in Javascript [duplicate]

This question already has answers here:
Getting key with the highest value from object
(9 answers)
Closed 9 months ago.
In Finding the max value of an attribute in an array of objects there are many (great) answers that report the highest value in an array, but they leave out the option that the object with the highest value would be the desired result to report.
I'm looking for the best way to search for the highest value in an array and return the object that has this value. For example, the expected result of checking this array:
{
"Intent": {
"FileComplaint": 0.000,
"UnsubscribeMe": 0.995,
"TrackRefund": 0.001,
"AskSwitchAccount": 0.00
}
would be: "UnsubscribeMe" or "UnsubscribeMe": 0.995.
Anyone who can help?
Edit:
I found a question that is better formulated than mine and it has great answers:
Getting key with the highest value from object
const obj={Intent:{FileComplaint:0,UndermineGovernment:0.45,UnsubscribeMe:.995,TrackRefund:.001,AskSwitchAccount:0}};
// Get the entries as a nested array of key/value pairs
const entries = Object.entries(obj.Intent);
// Sort the entries by value (index 1),
// and then pop off the last entry destructuring
// the key/value from that array in the process
const [key, value] = entries.sort((a, b) => a[1] > b[1]).pop();
// Log the resulting object
console.log({ [key]: value });

Iterating String.split() working differently than I expected [duplicate]

This question already has answers here:
Loop through an array in JavaScript
(46 answers)
What is the difference between ( for... in ) and ( for... of ) statements?
(18 answers)
Closed last year.
I am writing a simple javascript code to parse, and verify a chess position written in Forsyth–Edwards Notation (FEN).
The default chess position in this notation is given by,
const defaultFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
There are 6 components, I split the components by whitespace using String.split(" "), I now want to further split the first element of the resulting array by "/", which will give the state of each rank.
Running this code gives me an unintuitive result...
const defaultFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
const locations = defaultFEN.split(" ")[0];
for (let rank in locations.split("/")) {
console.log(rank);
}
I expected the output to be 8 Strings, delimited by "/", in the first portion of the defaultFEN string. Instead I get the numbers 0-7 printing out.
Interestingly, If I manually access this array, console.log(locations.split("/")[i]), for any number i in the interval [0-7], I see the result I intended.
Why are the numbers 0-7 printing out when using the iterative loop, but it works exactly as intended if I use a normal index based for loop?
There's nothing wrong with your split, but you should use for..of (MDN) instead:
for (let rank of locations.split("/")) {
console.log(rank);
}
... as for..in loop iterates over indexes (and those are 0..7 for 8-element array).
As a sidenote, it's (usually) a good idea to use const (and not let) in this iteration, as variable is assigned a value once each loop (and usually shouldn't be reassigned):
for (const rank of locations.split("/")) {
console.log(rank);
}

Create set of sets javascript

I have a group of arrays that I need to filter out duplicates. It needs to work in such a fashion that within each array, there are no duplicates, and within the total group, there are no two arrays that hold the same values.
The first part is easy - for each inner array, I can apply Set to the array and filter it out. So, given the matrix arrays I can apply the following to filter:
const sets : string[][] = arrays.map(arr=>[...new Set(arr)].sort());
This will give me an array of sets. How can I make this into a set of sets? As in, if sets=[[a, b],[c],[d, a],[c],[e]] I would like setOfSets to equal [[a, b],[c],[d, a],[e]]?
Applying setOfSets = [...new Set(sets)]; would not work, since arrays that are equal are not considered equal by default if they have different addresses. Is there a way to force set to check by value, or another effective way to create this effect?
Edit
Original matrix:
[[a, b, b],
[c,c],
[b,a],
[d,a],
[c,c],
[e,e]]
after creating and sorting sets:
[[a,b],
[c],
[a,b],
[d,a],
[c],
[e]]
desired result:
[[a,b],
[c],
[d,a],
[e]]
If the data in your set is easy to serialize, I would opt for a solution like this:
const data = [
["a", "b", "b"],
["c","c"],
["b","a"],
["d","a"],
["c","c"],
["e","e"]
];
// Create the "hash" of your set
const serializeSet = s => Array
.from(s)
.sort()
.join("___");
// Create a map (or object) that ensures 1 entry per hash
const outputMap = data
.map(xs => new Set(xs))
.reduce(
(acc, s) => acc.set(serializeSet(s), s),
new Map()
);
// Turn your Map and Sets back in to arrays
const output = Array
.from(outputMap.values())
.map(s => Array.from(s));
console.log(output);
To come up with a good hash function for your set, you need to have a good look at your data. For example:
When your arrays consist of single characters from a-z, like in my example above, we can sort those strings using a default sorter and then join the result using a character from outside the a-z range.
If your arrays consist of random strings or numbers, JSON.stringify(Array.from(s).sort()) is safer to use
When your arrays consist of plain objects, you could JSON.stringify its sorted elements, but watch out for differences in the order of objects properties! (e.g. {a: 1, b: 2} vs {b: 2, a: 1})

javascript sort function sorting wrong [duplicate]

This question already has answers here:
How to sort an array of integers correctly
(32 answers)
Closed 9 years ago.
Hello I have a textbox having values like
<input type="hidden" value="2,1,4,5,3,6,7,8,9,10,11,12" class="sortvalues" id="1_1_parent">
Now what I want to take the value of this textbox, want to split the values to array and then as last result I need a sorted array.
What I have done.
allsortedValues = $(".sortvalues").val();
allsortedValues = allsortedValues.split(",");
allsortedValues = allsortedValues.sort();
When I check the array
console.log(allsortedValues);
It shows
1,10,11,12,2,3,4,5,6,7,8,9
Sorting array as 1, 10, 11, 12, 2.....
I have even used
allsortedValues = allsortedValues.split(",").map(function(x){return parseInt(x)});
before applying sort and in other case I have even used parseInt like
for(var i = 0; i < allsortedValues.length; i++) {
allsortedValues[i] = parseInt(allsortedValues[i]);
}
before applying sort but in all cases result is same. Will some one guide what am I doing wrong?
You'll have to pass in a comparator function that converts the strings to numbers:
allsortedvalues = allsortedvalues.sort(function(a,b) {
return (+a) - (+b);
});
If there's a chance that some of your array entries aren't nicely-formatted numbers, then your comparator would have to get more complicated.
The construction (+a) involves the unary + operator, which doesn't do anything if a is already a number. However if a is not a number, the result of +a will be either the value of a when interpreted as a number, or else NaN. A string is interpreted as a number in the obvious way, by being examined and parsed as a string representation of a number. A boolean value would be converted as false -> 0 and true -> 1. The value null becomes 0, and undefined is NaN. Finally, an object reference is interpreted as a number via a call to its valueOf() function, or else NaN if that doesn't help.
It's equivalent to use the Number constructor, as in Number(a), if you like. It does exactly the same thing as +a. I'm a lazy typist.
If compareFunction is not supplied, elements are sorted by converting
them to strings and comparing strings in lexicographic ("dictionary"
or "telephone book," not numerical) order. For example, "80" comes
before "9" in lexicographic order, but in a numeric sort 9 comes
before 80.
To compare numbers instead of strings, the compare function can simply subtract b from a:
function compareNumbers(a, b)
{
return a - b;
}
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/sort

How to sort numbers correctly with Array.sort()? [duplicate]

This question already has answers here:
How to sort an array of integers correctly
(32 answers)
Closed 9 years ago.
In multiple browsers, the following code doesn't sort the numbers correctly:
a = new Array();
a.push(10);
a.push(60);
a.push(20);
a.push(30);
a.push(100);
document.write(a.sort())
It returns 10,100,20,30,60.
Anyone know why?
a.sort(function(a,b){return a - b})
These can be confusing.... check this link out.
I've tried different numbers, and it always acts as if the 0s aren't there and sorts the numbers correctly otherwise. Anyone know why?
You're getting a lexicographical sort (e.g. convert objects to strings, and sort them in dictionary order), which is the default sort behavior in Javascript:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort
array.sort([compareFunction])
Parameters
compareFunction
Specifies a function that defines the sort order. If omitted, the array is sorted lexicographically (in dictionary order) according to the string conversion of each element.
In the ECMAscript specification (the normative reference for the generic Javascript), ECMA-262, 3rd ed., section 15.4.4.11, the default sort order is lexicographical, although they don't come out and say it, instead giving the steps for a conceptual sort function that calls the given compare function if necessary, otherwise comparing the arguments when converted to strings:
13. If the argument comparefn is undefined, go to step 16.
14. Call comparefn with arguments x and y.
15. Return Result(14).
16. Call ToString(x).
17. Call ToString(y).
18. If Result(16) < Result(17), return −1.
19. If Result(16) > Result(17), return 1.
20. Return +0.
The default sort for arrays in Javascript is an alphabetical search. If you want a numerical sort, try something like this:
var a = [ 1, 100, 50, 2, 5];
a.sort(function(a,b) { return a - b; });
You can use a sort function :
var myarray=[25, 8, 7, 41]
myarray.sort( function(a,b) { return a - b; } );
// 7 8 25 41
Look at http://www.javascriptkit.com/javatutors/arraysort.shtml
try this:
a = new Array();
a.push(10);
a.push(60);
a.push(20);
a.push(30);
a.push(100);
a.sort(Test)
document.write(a);
function Test(a,b)
{
return a > b ? true : false;
}

Categories