Conceptualmente, me gustaría ordenar los datos de una sola columna de tipo variante, de forma similar a como se hace en Excel:
Aquí podemos ver que los Números se ordenan antes que las Cadenas antes que los Booleanos antes que los Errores. Entonces, me gustaría tener una función que funcione así en SQL:
SELECT * FROM table ORDER BY CASE WHEN type='number' THEN 0 WHEN type='string' THEN 1 /* ... */ END, SortFunction(variantData)Esto es lo que me gustaría lograr:
SortFunction necesita devolver un valor de un solo tipo de datos, por ejemplo, una cadena, un número o un tipo binario.Cualquier lenguaje de programación está bien, estoy más preocupado por una técnica para lograr esta clasificación similar a Excel.
Para un campo numérico, podemos mantenerlo tal cual, para un campo relacionado con fecha/hora podemos hacer una marca de tiempo de Unix, pero ¿cómo lo haríamos para un tipo de datos de cadena o binario?
Considere cada elemento como una matriz de bytes y aplique el Comparador:
import java.util.Arrays; import java.util.Comparator; public class SortAnyObjects { public static void main(String[] args) { Object[] arr = {1, 'c', '&', "z", "testing", "hello world", '文', 'å'}; byte[][] a = new byte[arr.length][]; // <---- The column is not initialized for (int i = 0; i < arr.length; i++) { if (arr[i] instanceof Integer) { a[i] = String.valueOf((int) arr[i]).getBytes(); } else if (arr[i] instanceof Character) { a[i] = String.valueOf((char) arr[i]).getBytes(); } else { // <---- Here expand your else condition as you expect the datatypes a[i] = ((String) arr[i]).getBytes(); } } Arrays.sort(a, new Comparator<byte[]>() { @Override public int compare( final byte[] o1, final byte[] o2 ) { if (o1 == null) { return 1; } if (o2 == null) { return -1; } if (o1 == o2) { return 0; } if (o2.length > o1.length) { return compare(o2, o1); } for (int i = 0; i < o1.length; i++) { if (o1[i] == o2[i]) { continue; } return Byte.compare(o1[i], o2[i]); } return 0; } }); System.out.println(Arrays.toString(a)); for (int i = 0; i < a.length; i++) { System.out.println(new String(a[i])); } } }Construiría esto sobre una función simple que ordena pares de predicados de tipo de datos y funciones de comparación. Luego, simplemente podemos ordenarlos de number , string , boolean , error , lo que sea.
Una versión simple, apenas probada de esa idea es la siguiente:
const multiSort = (cfgs) => (xs) => xs .sort ((a, b) => { const ia = cfgs .findIndex (([f]) => f (a)) const ib = cfgs .findIndex (([f]) => f (b)) return ia == ib ? cfgs [ia] [1] (a, b) : ia - ib }) const excelSorter = multiSort ([ [(x) => typeof x == 'number' && Number .isFinite (x), (a, b) => a < b ? -1 : a > b ? 1 : 0], [(x) => typeof x == 'string', (a, b) => a < b ? -1 : a > b ? 1 : 0], // or case-insensitive [(x) => typeof x == 'boolean', (a, b) => a ? b ? 0 : 1 : b ? -1 : 0], [isNaN, () => 0], [() => true, () => a < b ? -1 : a > b ? 1 : 0] // defaulting to JS's internal sort otherwise ]) console .log (excelSorter ( [1, true, "00A", "Something", -2.14, false, 1.29375e-17, 9, "Z", 2.4, NaN, "Hello", 2.98129e+30] )) //=> [-2.14, 1.29375e-17, 1, 2.4, 9, 2.98129e+30, "00A", "Hello", "Something", "Z", false, true, NaN] .as-console-wrapper {max-height: 100% !important; top: 0}Simplemente encontramos el índice del primer objeto de configuración cuya función de prueba devuelve verdadero para nuestro primer valor y el índice del uno para nuestro segundo valor. Si esos números son diferentes, devolvemos la diferencia en esos índices. Si son iguales, devolvemos el resultado de llamar a la función de comparación asociada en los dos valores.
Muchas variantes de esto son posibles. Es posible que queramos que la función en sí suministre el par final que se usa aquí, por lo que siempre hay una alternativa. Podríamos querer {test, compare} objetos en lugar de pares ordenados en una matriz. Es posible que deseemos cambiar esa versión final para que simplemente devuelva siempre 0 , en lugar de depender de las reglas de comparación de valores impares de JS.