Related
i have a Question. I was thinking long Time about it, but poorly i don´t find a answer.
I know the every method.
My Question is about this code section:
var tr = order.every((i) => stock[i[0]] >= i[1]);
My Questions are:
stock is an Object. Why i must write as an array?
Why it is i[0] in stock and then i[1] ?
Why this code checks the nested Arrays in const order ?
const order = [
["shirt", 5],
["shoes", 2]
];
const stock = {
shirt: 50,
height: 172,
mass: 120,
shoes: 6
};
var tr = order.every((i) => stock[i[0]] >= i[1]); /// return true
console.log(`tr:`,tr)
So, the square brackets can be used to access element inside the array by passing it's index e.g:
const arr = ["first", "second"];
const secondElement = arr[1] // index 1 means seconds element
and also square brackets can be used to access element inside the object by passing it's key e.g:
const obj = { first: 1, second: 2 };
const secondElement = object.second // Normal way to access value in object
const secondElementWithAnotherSyntax = object['second'] // another syntax, same thing
the cool thing about the other syntax shown is that you can pass variable to it, e.g :
const objKey = 'second'
const secondElement = obj[objKey]
Now let's look at your example, i is one element of the array order, which carries arrays itself, so i is also one of the two small arrays, i[0] is the string word in the beginning of the small arrays, so:
i[0] // is either 'shirt' or 'shoes'
and since stocks is an object that has those keys, you can access for example the value 50 by saying stocks['shirt'] or as in your case, stock[i[0]] ;)
now your second question: why should it be >= i[1] ?
because the order second item , aka i[1] is the number of items required/ordered, so this should always be less that your stock, you can't by 5 shirts from a place that has only 3 in the stock :)
1. stock is an Object. Why i must write as an array?
You can access properties of objects using brackets [].
Why do we need this?
To be able to access properties of objects dynamically, e.g. when you are looping though keys and want to get the values
Object.keys(data).forEach(function(key) {
console.log('Key : ' + key + ', Value : ' + data[key])
})
Sometimes there is no other way to access the value:
const json = {
"id":"1",
"some key with spaces": "48593"
};
console.log(json.some key with spaces); // obviously throws error
console.log(json['some key with spaces']); // prints "48593"
2. Why it is i[0] in stock and then i[1] ?
3. Why this code checks the nested Arrays in const order ?
The code goes through the orders, each order is an array so i[0] is the type of the order and i[1] is the quantity. the code checks if there are enough items in stock. To check if there are enough shirts you would do:
console.log(stock["shirts"] >= 5
Thats what the code in your example does, it just passes the key ("shirts") and quantity (5) dynamically.
May I suggest to try to use more expressive naming of the variables ?
An object property can be accessed through bracket notation, as in stock[orderedProductName] when using a variable - Property accessors
A concise but imho more readable version can be written using destructuring assignment
const order = [
["shirt", 5],
["shoes", 2]
];
const stock = {
shirt: 50,
height: 172,
mass: 120,
shoes: 6,
};
// original version
let inStock = order.every((i) => stock[i[0]] >= i[1]); /// return true
// more verbose version
// check if every item in array order satisfies the condition
// let's cycle over the array calling the element we're working on
// orderItem
inStock = order.every( orderItem => {
const orderedProductName = orderItem[0];
const orderedProductQuantity = orderItem[1];
// to access an object property we can use bracket notation
const stockProductQuantity = stock[orderedProductName];
// the condition to check: do we have enough products in stock ?
return stockProductQuantity >= orderedProductQuantity;
});
// a concise variation could make use of destructuring assignment.
// Here, when we take the order item array, we immediately assign
// each of its elements to the appropriate variable
//
// orderItem[0] or first array element -> productName
// orderItem[1] or second array element -> orderedQuantity
inStock = order.every(([productName, orderedQuantity]) =>
stock[productName] >= orderedQuantity
);
if(inStock) {
console.log('pack and ship');
}
else {
console.log('need to restock');
}
The every() method tests whether all elements in the array pass the test implemented by the provided function. It returns a Boolean value. If you want to read more Array.prototype.every()
In your code snippet you are checking that every item in order array has quantity less than the quantity available in stock.
To access the properties of a object you can use square notation also like arrays. To read more Bracket Notation
If you assigned more meaningful variables to the code you'd probably understand how this works better.
In one order (an array) we have two nested arrays. The first describes shirt/value, the other shoes/value. every is going to see if there is enough stock for both shirt and shoes by checking that the stockValue >= the items in the order.
When you every over the order array the callback for each iteration is one orderItem (['shirt', 5] first, then ['shoes', 2] for the second). We can assign the first element of each array to a variable called itemType, and the second to a variable called itemQty.
So when you see stock[i][0] we can translate that in the new code as stock[orderType] which is using bracket notation to locate the property value associated by that key in the stock object. We then check to see if that value >= than the itemQty.
const order=[["shirt",5],["shoes",2]],stock={shirt:50,height:172,mass:120,shoes:6};
const result = order.every(orderItem => {
const itemType = orderItem[0];
const itemQty = orderItem[1];
return stock[itemType] >= itemQty;
});
console.log(result);
In its most basic form, having an array of objects:
let arr = [
{val:"a"},
{val:"b"}
];
How can destructuring be used, to obtain only the values ['a', 'b'].
getting the first value is easy:
let [{val:res}] = arr; //res contains 'a'
Obtaining all values inside the array can be done with the rest operator:
let [...res] = arr; //res contains all objects
Combining those, I expected to be able to use:
let [...{val:res}] = arr; //undefined, expected all 'val's (['a', 'b'])
The above returns undefined (Tested in FF). Some further testing seems to indicate that adding the rest operator when using an object destructuring as well doesn't use the iteration, but gets back the original object, e.g. let [...{length:res}] = arr; //res= 2. Some other trials, such as let [{val:...res}] = arr; or let [{val}:...res] = arr; produce syntax errors.
It's easy enough to do with other methods, such as using map on the array, but mostly I stumble upon this problem while destructuring multiple levels (an array with objects which have their own property containing an array). Therefore I'm really trying to get around how to do it solely with destructuring.
For convenience: a test fiddle
edit
My apologies if I failed to explain the goal of the question. I'm not looking for a solution to a specific problem, only to find the correct syntax to use when destructuring.
Otherwise formulated, a first question would be: in the example above, why doesn't let [...{val:res}] = arr; return all values (['a', 'b']). The second question would be: what is the proper syntax to use a rest operator with a nested object destructuring? (pretty sure I've gotten some definitions mixed up here). It seems that the latter is not supported, but I haven't come across any documentation that (and why) it wouldn't be.
Why doesn't let [...{val:res}] = arr; return all values (['a', 'b'])?
You seem to confuse the rest syntax with array comprehensions.
If you assign a value to [someElements, ...someExpression], the value is tested to be iterable and then each element generated by the iterator is assigned to the respective someElements variable. If you use the rest syntax in the destructuring expression, an array is created and the iterator is ran till its end while filling the array with the generated values. Then that array is assigned to the someExpression.
All of these assignment targets can be other destructuring expressions (arbitrarily nested and recursively evaluated), or references to variable or properties.
So if you do let [...{val:res}] = arr, it will create an array and fill that with all the values from the iterator of arr:
let {val:res} = Array.from(arr[Symbol.iterator]())
You can see now why that ends up with undefined, and why using something like [...{length:res}] does yield a result. Another example:
let [{val:res1}, ...{length: res2}] = arr;
console.log(res1) // 'a'
console.log(res2) // 1 (length of `[{val: 'b'}]`)
How can destructuring be used to obtain only the values ['a', 'b']?
Not at all. Use the map method.
You can destructure nested objects like this
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Nested_object_and_array_destructuring
let arr = [
{val:"a"},
{val:"b"}
];
const [{val: valueOfA}, {val: valueOfB}] = arr
console.log(
valueOfA, valueOfB
)
Beside mapping with a callback for the value
let arr = [{ val: "a" }, { val: "b" }];
console.log(arr.map(o => o.val));
you could use deconstructiong inside of the paramter list and use only the value to return.
let arr = [{ val: "a" }, { val: "b" }];
console.log(arr.map(({val}) => val));
At this point of time you can use both For of loop with ES6 Object destructuring.
let arr = [{val:"a"},{val:"b"}];
for (const item in arr){
const {val} = arr[item];
console.log(val);
}
You can declare assignment target before destructuring assignment; at destructuring target, set values of assignments target indexes by from destructuring source
let arr1 = [{val: "a"}, {val: "b"}];
let arr2 = [{"foo":1,"arr":[{"val":"a"},{"val":"b"}]}
, {"foo":2,"arr":[{"val":"c"},{"val":"d"}]}];
let [res1, res2] = [[], []];
[{val: res1[0]}, {val: res1[1]}] = arr1;
[{arr: [{val:res2[0]}, {val:res2[1]}]}
, {arr: [{val:res2[2]}, {val:res2[3]}]}] = arr2;
console.log(res1, res2);
You can alternatively use rest element at target to collect values at source by including comma operator following object pattern to return value pulled from object
let arr = [{val: "a"}, {val: "b"}];
let [...res] = [({val} = arr[0], val), ({val} = arr[1], val)];
console.log(res)
In its most basic form, having an array of objects:
let arr = [
{val:"a"},
{val:"b"}
];
How can destructuring be used, to obtain only the values ['a', 'b'].
getting the first value is easy:
let [{val:res}] = arr; //res contains 'a'
Obtaining all values inside the array can be done with the rest operator:
let [...res] = arr; //res contains all objects
Combining those, I expected to be able to use:
let [...{val:res}] = arr; //undefined, expected all 'val's (['a', 'b'])
The above returns undefined (Tested in FF). Some further testing seems to indicate that adding the rest operator when using an object destructuring as well doesn't use the iteration, but gets back the original object, e.g. let [...{length:res}] = arr; //res= 2. Some other trials, such as let [{val:...res}] = arr; or let [{val}:...res] = arr; produce syntax errors.
It's easy enough to do with other methods, such as using map on the array, but mostly I stumble upon this problem while destructuring multiple levels (an array with objects which have their own property containing an array). Therefore I'm really trying to get around how to do it solely with destructuring.
For convenience: a test fiddle
edit
My apologies if I failed to explain the goal of the question. I'm not looking for a solution to a specific problem, only to find the correct syntax to use when destructuring.
Otherwise formulated, a first question would be: in the example above, why doesn't let [...{val:res}] = arr; return all values (['a', 'b']). The second question would be: what is the proper syntax to use a rest operator with a nested object destructuring? (pretty sure I've gotten some definitions mixed up here). It seems that the latter is not supported, but I haven't come across any documentation that (and why) it wouldn't be.
Why doesn't let [...{val:res}] = arr; return all values (['a', 'b'])?
You seem to confuse the rest syntax with array comprehensions.
If you assign a value to [someElements, ...someExpression], the value is tested to be iterable and then each element generated by the iterator is assigned to the respective someElements variable. If you use the rest syntax in the destructuring expression, an array is created and the iterator is ran till its end while filling the array with the generated values. Then that array is assigned to the someExpression.
All of these assignment targets can be other destructuring expressions (arbitrarily nested and recursively evaluated), or references to variable or properties.
So if you do let [...{val:res}] = arr, it will create an array and fill that with all the values from the iterator of arr:
let {val:res} = Array.from(arr[Symbol.iterator]())
You can see now why that ends up with undefined, and why using something like [...{length:res}] does yield a result. Another example:
let [{val:res1}, ...{length: res2}] = arr;
console.log(res1) // 'a'
console.log(res2) // 1 (length of `[{val: 'b'}]`)
How can destructuring be used to obtain only the values ['a', 'b']?
Not at all. Use the map method.
You can destructure nested objects like this
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Nested_object_and_array_destructuring
let arr = [
{val:"a"},
{val:"b"}
];
const [{val: valueOfA}, {val: valueOfB}] = arr
console.log(
valueOfA, valueOfB
)
Beside mapping with a callback for the value
let arr = [{ val: "a" }, { val: "b" }];
console.log(arr.map(o => o.val));
you could use deconstructiong inside of the paramter list and use only the value to return.
let arr = [{ val: "a" }, { val: "b" }];
console.log(arr.map(({val}) => val));
At this point of time you can use both For of loop with ES6 Object destructuring.
let arr = [{val:"a"},{val:"b"}];
for (const item in arr){
const {val} = arr[item];
console.log(val);
}
You can declare assignment target before destructuring assignment; at destructuring target, set values of assignments target indexes by from destructuring source
let arr1 = [{val: "a"}, {val: "b"}];
let arr2 = [{"foo":1,"arr":[{"val":"a"},{"val":"b"}]}
, {"foo":2,"arr":[{"val":"c"},{"val":"d"}]}];
let [res1, res2] = [[], []];
[{val: res1[0]}, {val: res1[1]}] = arr1;
[{arr: [{val:res2[0]}, {val:res2[1]}]}
, {arr: [{val:res2[2]}, {val:res2[3]}]}] = arr2;
console.log(res1, res2);
You can alternatively use rest element at target to collect values at source by including comma operator following object pattern to return value pulled from object
let arr = [{val: "a"}, {val: "b"}];
let [...res] = [({val} = arr[0], val), ({val} = arr[1], val)];
console.log(res)
I have a .txt file with all the scrabble letter quantities in:
A-9, B-2, C-2, D-4, E-12, F-2, G-3, H-2, I-9, J-1, K-1, L-4, M-2, N-6, O-8, P-2, Q-1, R-6, S-4, T-6, U-4, V-2, W-2, X-1, Y-2, Z-1
I am trying to get an array of objects from this, where the key is the letter, and the value is the number.
The problem I am having is where I am trying to set the key to be the first item in the array (that I split earlier) [A, 9].
The code I have is as follows. Any tips would be gratefully received :)
import fs from 'fs'
var output = fs.readFileSync('scrabble-quantities.txt', 'utf-8')
.trim()
.split(', ')
.map(item => item.split('-'))
.reduce((quantities, item) => {
quantities.push({
item[0]: item[1]
})
return quantities
}, [])
Thanks
I would use an object instead of an array. It's easier and more natural how JS works:
// ...
.reduce((quantities, item) => {
quantities[item[0]] = item[1];
return quantities;
}, {});
The resulting output object is then (in JSON notation):
{
"A": 9,
"B": 2,
// ...
"Z": 1
}
EDIT: mind the value type
If you want the value to be an actual number you will have to parse it in the assignment with:
parseInt(item[1], 10)
To create a key (property name) dynamically, you need to do one of two things:
In ES5 and earlier, you have to create the object and then set the property:
var o = {};
o[item[0]] = item[1];
In ES2015 (aka ES6) and later, you can use a dynamic property name in a property initializer via []:
// ES2015 (ES6) ONLY
quantities.push({
[item[0]]: item[1]
})
That said, I'd come at the problem differently, using regex and ending up with an object keyed by the letter rather than an array of objects:
var str = "A-9, B-2, C-2, D-4, E-12, F-2, G-3, H-2, I-9, J-1, K-1, L-4, M-2, N-6, O-8, P-2, Q-1, R-6, S-4, T-6, U-4, V-2, W-2, X-1, Y-2, Z-1";
var quantities = {};
str.match(/[A-Z]-\d/g).forEach(function(entry) {
quantities[entry.charAt(0)] = +entry.replace(/.-/, '');
});
console.log(quantities);
Then, looking up the quantity of a letter becomes quantities.A (or quantities[letter] if letter is a variable containing "A"):
console.log(quantities.A); // 9
Is it possible to sort the entries of a es6 map object?
var map = new Map();
map.set('2-1', foo);
map.set('0-1', bar);
results in:
map.entries = {
0: {"2-1", foo },
1: {"0-1", bar }
}
Is it possible to sort the entries based on their keys?
map.entries = {
0: {"0-1", bar },
1: {"2-1", foo }
}
According MDN documentation:
A Map object iterates its elements in insertion order.
You could do it this way:
var map = new Map();
map.set('2-1', "foo");
map.set('0-1', "bar");
map.set('3-1', "baz");
var mapAsc = new Map([...map.entries()].sort());
console.log(mapAsc)
Using .sort(), remember that the array is sorted according to each character's Unicode code point value, according to the string conversion of each element. So 2-1, 0-1, 3-1 will be sorted correctly.
Short answer
new Map([...map].sort((a, b) =>
// Some sort function comparing keys with a[0] b[0] or values with a[1] b[1]
))
If you're expecting strings: As normal for .sort you need to return -1 if lower and 0 if equal; for strings, the recommended way is using .localeCompare() which does this correctly and automatically handles awkward characters like ä where the position varies by user locale.
So here's a simple way to sort a map by string keys:
new Map([...map].sort((a, b) => String(a[0]).localeCompare(b[0])))
...and by string values:
new Map([...map].sort((a, b) => String(a[1]).localeCompare(b[1])))
These are type-safe in that they won't throw an error if they hit a non-string key or value. The String() at the start forces a to be a string (and is good for readability), and .localeCompare() itself forces its argument to be a string without hitting an error.
In detail with examples
tldr: ...map.entries() is redundant, just ...map is fine; and a lazy .sort() without passing a sort function risks weird edge case bugs caused by string coercion.
The .entries() in [...map.entries()] (suggested in many answers) is redundant, probably adding an extra iteration of the map unless the JS engine optimises that away for you.
In the simple test case, you can do what the question asks for with:
new Map([...map].sort())
...which, if the keys are all strings, compares squashed and coerced comma-joined key-value strings like '2-1,foo' and '0-1,[object Object]', returning a new Map with the new insertion order:
Note: if you see only {} in SO's console output, look in your real browser console
const map = new Map([
['2-1', 'foo'],
['0-1', { bar: 'bar' }],
['3-5', () => 'fuz'],
['3-2', [ 'baz' ]]
])
console.log(new Map([...map].sort()))
HOWEVER, it's not a good practice to rely on coercion and stringification like this. You can get surprises like:
const map = new Map([
['2', '3,buh?'],
['2,1', 'foo'],
['0,1', { bar: 'bar' }],
['3,5', () => 'fuz'],
['3,2', [ 'baz' ]],
])
// Compares '2,3,buh?' with '2,1,foo'
// Therefore sorts ['2', '3,buh?'] ******AFTER****** ['2,1', 'foo']
console.log('Buh?', new Map([...map].sort()))
// Let's see exactly what each iteration is using as its comparator
for (const iteration of map) {
console.log(iteration.toString())
}
Bugs like this are really hard to debug - don't risk it!
If you want to sort on keys or values, it's best to access them explicitly with a[0] and b[0] in the sort function, like above; or with array destructuring in the function arguments:
const map = new Map([
['2,1', 'this is overwritten'],
['2,1', '0,1'],
['0,1', '2,1'],
['2,2', '3,5'],
['3,5', '2,1'],
['2', ',9,9']
])
// Examples using array destructuring. We're saying 'keys' and 'values'
// in the function names so it's clear and readable what the intent is.
const sortStringKeys = ([a], [b]) => String(a).localeCompare(b)
const sortStringValues = ([,a], [,b]) => String(a).localeCompare(b)
console.log('By keys:', new Map([...map].sort(sortStringKeys)))
console.log('By values:', new Map([...map].sort(sortStringValues)))
And if you need a different comparison than alphabetical order of strings, don't forget to always make sure you return -1 and 1 for before and after, not false or 0 as with raw a[0] > b[0] because that is treated as equals.
Convert Map to an array using Array.from, sort array, convert back to Map, e.g.
new Map(
Array
.from(eventsByDate)
.sort((a, b) => {
// a[0], b[0] is the key of the map
return a[0] - b[0];
})
)
I would suggest to use a custom iterator for your map object to achieve a sorted access, like so:
map[Symbol.iterator] = function* () {
yield* [...map.entries()].sort((a, b) => a[0].localeCompare(b[0]));
}
Using an iterator has the advantage of that it has only to be declared once. After adding/deleting entries in the map, a new for-loop over the map would automatically reflect this changes using an iterator. Sorted copies as shown in most of the above answers would not as they only reflect the map's state at exactly one point in time.
Here's the complete working example using your initial situation.
var map = new Map();
map.set('2-1', { name: 'foo' });
map.set('0-1', { name: 'bar' });
for (let [key, val] of map) {
console.log(key + ' - ' + val.name);
}
// 2-1 - foo
// 1-0 - bar
map[Symbol.iterator] = function* () {
yield* [...map.entries()].sort((a, b) => a[0].localeCompare(b[0]));
}
for (let [key, val] of map) {
console.log(key + ' - ' + val.name);
}
// 1-0 - bar
// 2-1 - foo
map.set('2-0', { name: 'zzz' });
for (let [key, val] of map) {
console.log(key + ' - ' + val.name);
}
// 1-0 - bar
// 2-0 - zzz
// 2-1 - foo
Regards.
The idea is to extract the keys of your map into an array. Sort this array. Then iterate over this sorted array, get its value pair from the unsorted map and put them into a new map. The new map will be in sorted order. The code below is it's implementation:
var unsortedMap = new Map();
unsortedMap.set('2-1', 'foo');
unsortedMap.set('0-1', 'bar');
// Initialize your keys array
var keys = [];
// Initialize your sorted maps object
var sortedMap = new Map();
// Put keys in Array
unsortedMap.forEach(function callback(value, key, map) {
keys.push(key);
});
// Sort keys array and go through them to put in and put them in sorted map
keys.sort().map(function(key) {
sortedMap.set(key, unsortedMap.get(key));
});
// View your sorted map
console.log(sortedMap);
You can convert to an array and call array soring methods on it:
[...map].sort(/* etc */);
Unfortunately, not really implemented in ES6. You have this feature with OrderedMap.sort() from ImmutableJS or _.sortBy() from Lodash.
One way is to get the entries array, sort it, and then create a new Map with the sorted array:
let ar = [...myMap.entries()];
sortedArray = ar.sort();
sortedMap = new Map(sortedArray);
But if you don't want to create a new object, but to work on the same one, you can do something like this:
// Get an array of the keys and sort them
let keys = [...myMap.keys()];
sortedKeys = keys.sort();
sortedKeys.forEach((key)=>{
// Delete the element and set it again at the end
const value = this.get(key);
this.delete(key);
this.set(key,value);
})
2 hours spent to get into details.
Note that the answer for question is already given at https://stackoverflow.com/a/31159284/984471
However, the question has keys that are not usual ones,
A clear & general example with explanation, is below that provides some more clarity:
Some more examples here: https://javascript.info/map-set
You can copy-paste the below code to following link, and modify it for your specific use case: https://www.jdoodle.com/execute-nodejs-online/
.
let m1 = new Map();
m1.set(6,1); // key 6 is number and type is preserved (can be strings too)
m1.set(10,1);
m1.set(100,1);
m1.set(1,1);
console.log(m1);
// "string" sorted (even if keys are numbers) - default behaviour
let m2 = new Map( [...m1].sort() );
// ...is destructuring into individual elements
// then [] will catch elements in an array
// then sort() sorts the array
// since Map can take array as parameter to its constructor, a new Map is created
console.log('m2', m2);
// number sorted
let m3 = new Map([...m1].sort((a, b) => {
if (a[0] > b[0]) return 1;
if (a[0] == b[0]) return 0;
if (a[0] < b[0]) return -1;
}));
console.log('m3', m3);
// Output
// Map { 6 => 1, 10 => 1, 100 => 1, 1 => 1 }
// m2 Map { 1 => 1, 10 => 1, 100 => 1, 6 => 1 }
// Note: 1,10,100,6 sorted as strings, default.
// Note: if the keys were string the sort behavior will be same as this
// m3 Map { 1 => 1, 6 => 1, 10 => 1, 100 => 1 }
// Note: 1,6,10,100 sorted as number, looks correct for number keys
Hope that helps.
The snippet below sorts given map by its keys and maps the keys to key-value objects again. I used localeCompare function since my map was string->string object map.
var hash = {'x': 'xx', 't': 'tt', 'y': 'yy'};
Object.keys(hash).sort((a, b) => a.localeCompare(b)).map(function (i) {
var o = {};
o[i] = hash[i];
return o;
});
result: [{t:'tt'}, {x:'xx'}, {y: 'yy'}];
Perhaps a more realistic example about not sorting a Map object but preparing the sorting up front before doing the Map. The syntax gets actually pretty compact if you do it like this. You can apply the sorting before the map function like this, with a sort function before map (Example from a React app I am working on using JSX syntax)
Mark that I here define a sorting function inside using an arrow function that returns -1 if it is smaller and 0 otherwise sorted on a property of the Javascript objects in the array I get from an API.
report.ProcedureCodes.sort((a, b) => a.NumericalOrder < b.NumericalOrder ? -1 : 0).map((item, i) =>
<TableRow key={i}>
<TableCell>{item.Code}</TableCell>
<TableCell>{item.Text}</TableCell>
{/* <TableCell>{item.NumericalOrder}</TableCell> */}
</TableRow>
)
As far as I see it's currently not possible to sort a Map properly.
The other solutions where the Map is converted into an array and sorted this way have the following bug:
var a = new Map([[1, 2], [3,4]])
console.log(a); // a = Map(2) {1 => 2, 3 => 4}
var b = a;
console.log(b); // b = Map(2) {1 => 2, 3 => 4}
a = new Map(); // this is when the sorting happens
console.log(a, b); // a = Map(0) {} b = Map(2) {1 => 2, 3 => 4}
The sorting creates a new object and all other pointers to the unsorted object get broken.
Slight variation - I didn't have spread syntax and I wanted to work on an object instead of a Map.
Object.fromEntries(Object.entries(apis).sort())
Here is function that sort Map() by decreasing.
function groupBy(list, keyGetter) {
const map = new Map();
list.forEach((item) => {
const key = keyGetter(item);
const collection = map.get(key);
if (!collection) {
map.set(key, [item]);
} else {
collection.push(item);
}
});
const sortedMap = new Map();
[...map].sort((a, b) => b[1].length - a[1].length).forEach(e => sortedMap.set(e[0], e[1]));
return sortedMap;
}
const test = groupBy(array, item => item.fieldName);