对各种数据类型进行排序的算法

Algorithm to sort various data types

从概念上讲,我想对变体类型的单列数据进行排序,类似于 Excel:

中的做法

在这里我们可以看到数字在字符串之前在布尔之前在错误之前排序。所以,我想在 SQL:

中有一个像这样工作的函数
SELECT * FROM table ORDER BY
  CASE WHEN type='number' THEN 0 WHEN type='string' THEN 1 /* ... */ END,
  SortFunction(variantData)

这是我想要完成的:

任何编程语言都可以,我更关心的是实现这种 Excel 类排序的技术。

对于数字字段,我们可以保持原样,对于 date/time-related 字段,我们可以使用 unix 时间戳,但是对于字符串或二进制数据类型我们如何做呢?

将每个元素视为字节数组并应用比较器:

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]));
        }
    }

}

我会在一个简单的函数之上构建它,该函数对 data-type 谓词和比较器函数进行排序。然后我们可以简单地从 number,到 string,到 boolean,到 error,到任何顺序。

该想法的一个简单 barely-tested 版本如下:

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}

我们只需找到第一个配置对象的索引,其测试函数 return 为我们的第一个值和第二个值的索引。如果这些数字不同,我们 return 这些指数的差异。如果它们相同,我们 return 对两个值调用相关比较器函数的结果。

这有很多变体。我们可能希望函数本身提供此处使用的最后一对,因此总有回退。我们可能想要 {test, compare} 个对象而不是数组中的有序对。我们可能希望将最终版本更改为简单地总是 return 0,而不是依赖于 JS 的奇数比较规则。