Sort array by Criticality [duplicate] - javascript

This question already has answers here:
javascript sorting array based on another array
(1 answer)
Sort an array in the same order of another array
(4 answers)
Closed 3 years ago.
I have a criticality array and I want to sort by criticality, something like this:
let criticalityTypes = ['CRITICALITY_LOW', 'CRITICALITY_HIGH', 'CRITICALITY_MEDIUM'];
I get this order randomly, sometimes ** CRITICALITY_LOW ** comes in position 1 of the matrix ie either position 2, or 'CRITICALITY_MEDIUM' in 0 position,
What I want to do is order in the following order, regardless of the order that comes to me, sometimes I have just one criticality, or two:
['CRITICALITY_HIGH', 'CRITICALITY_MEDIUM', 'CRITICALITY_LOW'];
I tried to use sort function to order what I've done so far is this:
return criticalityTypes.sort((a, b) => {
if (a < b) return -1;
if (a > b) return 1;
});
But without success, any help?

You could take an object with the wanted order and sort by the delta of the values.
var criticalityTypes = ['CRITICALITY_LOW', 'CRITICALITY_HIGH', 'CRITICALITY_MEDIUM'],
order = { CRITICALITY_HIGH: 1, CRITICALITY_MEDIUM: 2, CRITICALITY_LOW: 3 };
criticalityTypes.sort((a, b) => order[a] - order[b]);
console.log(criticalityTypes);

Just another way:
let criticalityTypes = ['CRITICALITY_LOW', 'CRITICALITY_HIGH', 'CRITICALITY_MEDIUM'];
let orderedItems = [];
let desiredOrder = ['CRITICALITY_HIGH', 'CRITICALITY_MEDIUM', 'CRITICALITY_LOW'];
for (var i = 0; i < desiredOrder.length; i++) {
if (criticalityTypes.indexOf(desiredOrder[i]) > -1) {
orderedItems.push(desiredOrder[i]);
}
}
console.log(orderedItems);

The problem here is that you as the consumer of the api, do not have any clue what an "order" means for this items, as they are not "quantized", they are ideas, not an integer that you could call 'order' so you know what is what, the string is just for the display anyway.
Since you can not change the api, BUT they are always only these 3 and you always want them in the same order, you can mock your current call, put this as a 'placeholder' comparer so that you mock the calls to this function, until someones gives you something that you can use numericaly to determine an order, 'ascending' or 'descending' requires something quantized to have a meaning.
function criticalityTypes(a,b){
return ['CRITICALITY_HIGH', 'CRITICALITY_MEDIUM', 'CRITICALITY_LOW'];
}

Related

Why do I get an endless loop using moment.js?

I got the following string-array:
cohortsDates =
[
'2020-11', '2021-01',
'2021-02', '2021-03',
'2021-04', '2020-10',
'2021-05', '2020-12',
'2021-07'
]
Now I try to sort it that the dates are in an ascending order from 2020-10 to 2021-07 with this code:
cohortsDates.forEach((month) => {
for(var i = 0; i < cohortsDates.length; i++ ) {
if(moment(cohortsDates[i+1]) < moment(cohortsDates[i])) {
var swap = cohortsDates[i]
cohortsDates[i] = cohortsDates[i+1]
cohortsDates[i+1] = swap
}
}
})
console.log(cohortsDates)
But all I get is an endless loop and the sorted array never prints out. Does somebody know, what can I do to fix it?
When i === cohortsDates.length-1 (i.e. you are looking at the last item in your for loop) you test:
if(moment(cohortsDates[i+1]) < moment(cohortsDates[i])) {
Where cohortsDates[i+1] will always be undefined and thus less than the previous value.
So you swap them and assign cohortsDates[i] to cohortsDates[i+1].
This increases cohortsDates.length by 1 so the end condition of the for loop doesn't apply.
You now loop again and cohortsDates[i+1] is still undefined so it goes infinite.
JS has a built-in sort method to do this. Don't reinvent the wheel.
You don't exactly have the most efficient sorting algorithm. When sorting, you should use javascript's array.sort:
cohortsDates.sort((a, b) => moment(a) < moment(b) ? -1 : 1);
The sort method will loop over the array and call the function you passed as an argument with two of the values as parameters. If the function returns a negative number, that means a is less than b, a positive number means a is greater than b.

Using reduce() changes order of array [duplicate]

This question already has answers here:
Does JavaScript guarantee object property order?
(13 answers)
Closed 4 years ago.
Within the example script I have generated two arrays I would like to combine to a single row:
var testHeaders = ["aLabel", "bLabel", "cLabel","dLabel","eLabel"];
and
var testValue = ["aValue","bValue", "cValue","dValue","eValue"];
What I am trying to achieve is a string like { aLabel = aValue, bLabel = bValue, ... } that can be used to upload into BigQuery (the data upload job works).
I found a piece of code that almost does this, but somehow it changes the order of the elements within the two arrays.
var code = testValue.reduce(function(obj, value, index) {
obj[testHeaders[index]] = value;
return obj
}, {})
However, the result does mix up the order of the arrays as seen below. I am not capable of figuring out why the order changes. As far as I know, reduce() should work its way from left to right in an array.
The returned object is:
{
aLabel = aValue,
dLabel = dValue,
bLabel = bValue,
eLabel = eValue,
cLabel = cValue
}
You can use map and join:
var testHeaders = ["aLabel", "bLabel", "cLabel","dLabel","eLabel"];
var testValue = ["aValue","bValue", "cValue","dValue","eValue"];
var res = '{' + testHeaders.map((label, i) => `${label}=${testValue[i]}`).join(',') + '}';
console.log(res);
As vlaz pointed out, you are creating neither a string or a new array, but an object. And just like maps, objects do not have a set order of keys in JavaScript. hence, there is quite a chance of getting another order in the object than in both arrays.

Why is the Array.sort() method in my Javascript program unstable? [duplicate]

This question already has answers here:
Fast stable sorting algorithm implementation in javascript
(16 answers)
Closed 6 years ago.
Here is my jsFiddle:
//Change this variable to change the number of players sorted
var numberOfPlayers = 15;
var teams = [];
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for(var a=0; a<numberOfPlayers; a++){
updateStandings();
teams.push(new Team(alphabet.charAt(a)));
}
console.log("Teams:");
for(var x=0; x<teams.length; x++){
console.log(teams[x].name);
}
//Functions and such
function updateStandings(){
teams.sort(function(a, b) {
if(a.score == b.score){
if(a.tiebreak == b.tiebreak){
return teams.indexOf(a)-teams.indexOf(b);
}else{
return b.tiebreak-a.tiebreak;
}
}else{
return b.score-a.score;
}
});
}
function Team(name){
this.name = name;
this.score = 0;
this.tiebreak = 0;
}
I assumed the problem was that javascript sorting was unstable, and changed my compare function, but it still does not work.
The generic approach to stable sorting in JS is as follows:
function stable_sort(array, sortfunc) {
function _sortfunc(a, b) { return sortfunc(array[a], array[b]) || a - b; }
return array.map((e, i) => i) . sort(_sortfunc) . map(i => array[i]);
}
What this actually does is to sort a list of indices. Then it maps the sorted list of indices back to the original array. The sort function is rewritten to compare the values in the array at those indices, and if they are equal then fall back to a comparison of indices themselves.
This approach avoids the problem in your code which is that it is doing indexOf look-ups into an array which is the middle of being sorted.
This question could be informative.
According to the documentation, sort method is not required to be stable: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort In some browsers it is stable, in some not.
You do need to change the compare function, but not in the way that you tried. The reason is that you compare
return teams.indexOf(a)-teams.indexOf(b);
in the current array. It means that if the order of a and b has changed on the previous steps, your sorting routine will preserve this new order, not the one that these elements had in the beginning.
There are different ways to solve it. For example, you can create a copy of the array before sorting and execute indexOf on this copy. It will preserve the order that elements had had before sorting started.
But if your know that order in advance, you can also use this knowledge. For example, if before sorting the teams was sorted by their names, you can compare names as strings instead of positions in the array, it would be much more efficient than the first option.
Because JS' sorting is typically unstable. From §22.1.3.24 of the spec:
The elements of this array are sorted. The sort is not necessarily stable (that is, elements that compare equal do not necessarily remain in their original order).
Your teams are created with identical properties except their name, so the line actually performing the sort is:
return teams.indexOf(a)-teams.indexOf(b);
Because you're calling indexOf, it searches for the item (and its index) each repetition of the sort. Sorting mutates the array (from MDN: it "sorts the elements of an array in place and returns the array").
You are searching for the item within the same array you are sorting, so the index may change on each iteration. Done correctly (relatively speaking), you could produce a never-ending sort with that.
For example:
const data = [1, 3, 2, 4];
let reps = 0;
data.sort((a, b) => {
console.log(data);
const ia = data.indexOf(a), ib = data.indexOf(b);
if (ia === ib || reps > 50) {
return 0;
} else if (ia < ib) {
return 1;
} else if (ib < ia) {
return -1;
}
});

Fill Arrays with random values

I have two 1D arrays and I want to fill them with 10 unique random x,y values in Processing.
For example:
x y
- -
3, 9
2, 4
6, 2
7, 5
My arrays are:
Table1 for the X values and
Table2 for the Y values.
My issue is if the number 3,9 exists already I don't want 9,3 to be stored in the arrays.
I can identify when x,y value (or y,x) already exists but once I replace it I cannot check if the new generated random number exist in the previous indexes.
This is what I have tried so far. However if 3 values aldready exists, the arrays Table1 and Table2 will store only 7 values instead of 10.
for (int i=0; i<10; i++) {
x=(int)random(6);
y=(int)random(6);
if ((Table1[i] != x && Table2[i] != y) || (Table1[i] != y && Table2[i] != x))
{
Table1[i] = x;
Table2[i] = y;
}
Any ideas how to control that?
I can think about only two ways of achieving it, and none is ideal.
Check if the numbers you generated already exists, and if it's the case, generate anothers until you get a unique combination. It could be expensive with a small range of possibilities, because it's random, and if you're very unlucky you could even end in an infinite loop...
Create an array containing every possible combination. Then, instead of generating random numbers, you'll generate a random index into this array (an integer in [0;array.length[). After that, you'll have to remove the choosen combination from the array (that way it won't be available for the next loop), and the inverse of it (if you picked (9;3), you have to remove (9;3) AND (3;9)).
I have this code that might help you,
first declare your arrays :
var a = [];
var b = [];
then you can call a function that does everything for you
fill(a,b)
The definition of this function should be something like this :
function fill(a, b) {
var arr = [];
while(arr.length<10) {
var pair = randomPair();
if (arr.indexOf(pair.join(','))==-1 || arr.indexOf(pair.reverse().join(','))==-1) {
a.push(pair[0]);
b.push(pair[1]);
arr.push(pair.join(','));
}
}
}
then the defintion of other used function is :
function randomPair () {
return [ parseInt(Math.random()*7) , parseInt(Math.random()*7) ]
}
so, obviously, the randomPair function returns 2 values x and y. the fill function tests if the pair already exists or not in normal order or reversed order. if not it's added both a, and b which are references to your main arrays;
I see no other option as to walk to the whole arrays again to check if they contains your new generated value(s).

Associative array loop order [duplicate]

This question already has answers here:
Elements order in a "for (… in …)" loop
(10 answers)
Closed 9 years ago.
I have an associative array (object) in wich I store data loaded from a 3rd party.
// 3rdPartyData is also an associative array
for(var key in 3rdPartyData) {
cookie[key] = 3rdPartyData[key];
}
My object gets stored into a cookie at the end and gets loaded form a cookie before (or created {} if no cookie exists).
Each page view the data from the 3rd party gets added or updated in my cookie array.
Question: If I wore to look the cookie, would the loop always get each key in the order they wore added to it or would the order be changed?
If so can anyone provide an idea on how to manage something like this?
The order of keys in for(var key in some_object) can be any, and certainly is not always sorted, but you can force the order to be the one you want:
for(var key in Object.keys(3rdPartyData).sort(keysSorter) {
cookie[key] = 3rdPartyData[key];
}
keysSorter = function(a, b) {
if (a === b) { // Should not actually be the case when sorting object keys
return 0;
}
// Compare a and b somehow and return 1 or -1 accordingly
return a < b ? 1 : -1;
}
And to make sure Object.keys() will work:
Object.keys = Object.keys || function(o) {
var result = [];
for(var name in o) {
if (o.hasOwnProperty(name))
result.push(name);
}
return result;
};

Categories