Last week, that is, on February 13, 2017, I asked a question.
How to sort a two dimensional array by columns in Javascript?
But that works for sorting a single column. When two elements of the column to sort are the same, it should be able to sort that sector by another column, but it doesn't.
The array I want to sort is the following:
var matriz = [
//Columnas: 0 1 2 3 4
/*Filas: 0*/ [9,5,3,2,7],
/* 1*/ [7,9,5,4,3],
/* 2*/ [8,4,6,0,1],
/* 3*/ [9,9,6,2,1]
]
With the current algorithm, sorting column 3 , the answer is as follows:
var matriz = [
//Columnas: 0 1 2 3 4
/*Filas: 0*/ [7,9,5,4,3],
/* 1*/ [9,5,3,2,7],
/* 2*/ [9,9,6,2,1],
/* 3*/ [8,4,6,0,1]
]
It's not too bad, it's sorted 4 2 2 0
, but the rows that have the 2 , should be sorted by the columns I want.
To be exact, the function that sorts should receive an array (a sequence) with all the columns that I want to sort, for example, [3,0,1,2,4]
. This means that first it sorts by column 3, in case they are equal ( 2 ), it sorts those by 0, but 9 is also the same, so it sorts by 1, and it would be sorted, but just in case, too order by 1, 2 and 4.
Also, to make it more general, it would be good to change whether the column is ascending or descending, for this, instead of an array it should be a matrix, the first column is the number of the column to sort, and the second column is a boolean indicating true
whether it is descending, and false
whether it is descending.
var columnas = [// Columna - esDescendente
[ 3, true ],
[ 0, true ],
[ 1, true ],
[ 2, false],
[ 4, false]
]
With this parameter, the result should be the following:
var matriz = [
//Columnas: 0 1 2 3 4
/*Filas: 0*/ [7,9,5,4,3],
/* 1*/ [9,9,6,2,1],
/* 2*/ [9,5,3,2,7],
/* 3*/ [8,4,6,0,1]
]
The sort order is not static, but is generated by a function.
function generar_compara(columna,esDescendente)
{
var menos=1-2*esDescendente
var devuelve="return a["+columna+"]>=b["+columna+"]?"+menos+":"+(-menos)
return Function("a","b",devuelve)
}
console.log(generar_compara(0,true))
console.log(generar_compara(1,false))
According to the arguments that I indicate, it generates a different criterion function for me .
0, false
->function anonymous(a,b/**/) {return a[0]>=b[0]?-1:1}
1, true
->function anonymous(a,b/**/) {return a[1]>=b[1]?1:-1}
My question is: How would the criteria be if I want to order, for example, as follows [3,true],[0,true],[1,true],[2,false],[4,false]
? and starting from the example function, how can I build a generator of similar functions, to make it more general?
A possible solution is to use a recursive function that goes through the column looking for the largest row and, if not found, looks at the next one.
To control which columns to check, you can use a control array, the same size as the array to check, with true or false as appropriate to use or ignore them in the loop.
For example:
The issue of choosing the order of the column would be to add the address in the control matrix and manage it from the recursive function with a conditional.
The criterion function would have to iterate through the array
columnas
, each element of that array contains a pair of values, like this row[3,true]
, the3
is the column, thetrue
is indicates whether it is descending.It should be something like this:
But since the method
sort
does not send the parametercolumnas
, the function must be generated withFunction
, so I convert the function to a text string, inserting the arraycolumnas
withJSON.stringify
.In order to be able to order by different
criterios
, instead of supplying an array with[3,false]
, where3
is the column andfalse
indicates if it isASC o DESC
, it occurs to me that to make it more "flexible" you could supply an array with[3,fn]
, wherefn
is a function that we are going to apply to order the matrix.For example:
Then, using this "criteria" array, it would remain to order the matrix applying the first criterion of the array and depending on whether the column values are repeated in the ordered rows, apply the following criterion to them.
demonstration:
Expanding on the same OP's answer, you don't need to use Function (which is a form of eval and is bad practice, as well as being unintuitive for the reader). You can achieve the same thing by simply returning a function expression.
And for the same it can be expressed as: