对各种数据类型进行排序的算法
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)
这是我想要完成的:
SortFunction
需要return 单一数据类型的值,例如字符串、数字或二进制类型。
- 如果有必要,我可以限制函数中文本字段的长度(例如,如果我们有一个 10,000 个字符的字符串,只需将其限制为前 100 个字符)。
任何编程语言都可以,我更关心的是实现这种 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 的奇数比较规则。
从概念上讲,我想对变体类型的单列数据进行排序,类似于 Excel:
中的做法在这里我们可以看到数字在字符串之前在布尔之前在错误之前排序。所以,我想在 SQL:
中有一个像这样工作的函数SELECT * FROM table ORDER BY
CASE WHEN type='number' THEN 0 WHEN type='string' THEN 1 /* ... */ END,
SortFunction(variantData)
这是我想要完成的:
SortFunction
需要return 单一数据类型的值,例如字符串、数字或二进制类型。- 如果有必要,我可以限制函数中文本字段的长度(例如,如果我们有一个 10,000 个字符的字符串,只需将其限制为前 100 个字符)。
任何编程语言都可以,我更关心的是实现这种 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 的奇数比较规则。