背景
- 项目排序需要根据以下不同类型字段排序。
(null) 项目特殊的值
‘--’ 项目为空的占位
日期 2020-01-01
区间 (10,20.1]
数字 100
版本号 10.01.17
中文 支付宝
英文 Alipay
其它的
- 支持多字段排序
以下是代码实现
const _number = "number";
const _zh = "zh";
const _en = "en";
const _date = "date";
const _range = "range";
const _version = "version";
const _empty = "--";
const _null = "null";
const _null2 = "(null)";
const numberReg = /^[-]?\d+(\.?\d)?\d*$/;
const versionReg = /^(\d{1,2}\.){2,}\d{1,2}$/;
const rangeReg =
/^[\(|\[]([-|+]?[∞|\d]+(\.?\d)?\d*){1},(([-|+]?[∞|\d]+(\.?\d)?\d*){1})[\)|\]]$/;
const dateReg = /^\d{4}([-\/])\d{2}(\1\d{2})?$/;
const enReg = /^[a-zA-Z]+/;
const zhReg = /[\u4e00-\u9fa5]/;
const emptyReg = /^--$/;
const NULL = ["null", "(null)"];
const ORDER_PROP_ASC = "asc";
const ORDER_PROP_DESC = "desc";
const sortConfig = {
sortWeight: {
[_number]: 1,
[_zh]: 2,
[_en]: 3,
[_date]: 4,
[_range]: 5,
[_version]: 6,
[_empty]: 100,
[_null]: 101,
[_null2]: 102,
},
sortMappingFn(sortWeight) {
const _mapping = [
{
reg: emptyReg,
weight: sortWeight[_empty],
},
{
reg: numberReg,
weight: sortWeight[_number],
},
{
reg: versionReg,
weight: sortWeight[_version],
},
{
reg: rangeReg,
weight: sortWeight[_range],
},
{
reg: dateReg,
weight: sortWeight[_date],
},
{
reg: enReg,
weight: sortWeight[_en],
},
{
reg: zhReg,
weight: sortWeight[_zh],
},
];
return _mapping;
},
};
function getCompareResult(
a,
b,
props,
rev,
fieldConfigs = [],
fieldConfigsIndex = 0,
mixedSort
) {
if (NULL.includes(a[props])) {
return 1 * rev;
}
if (NULL.includes(b[props])) {
return -1 * rev;
}
if (a[props] === b[props]) {
return getCompareResultByDeep(
a,
b,
fieldConfigsIndex,
fieldConfigs,
mixedSort
);
}
if (dateReg.test(a[props]) && dateReg.test(b[props])) {
return (Date.parse(a[props]) - Date.parse(b[props])) * rev;
}
if (rangeReg.test(a[props]) && rangeReg.test(b[props])) {
if (a[props].includes("-∞")) return -1 * rev;
if (a[props].includes("+∞")) return 1 * rev;
if (b[props].includes("-∞")) return 1 * rev;
if (b[props].includes("+∞")) return -1 * rev;
const n1 = a[props].slice(a[props].indexOf(",") + 1, a[props].length - 1);
const n2 = b[props].slice(b[props].indexOf(",") + 1, b[props].length - 1);
return (Number(n1) - Number(n2)) * rev;
}
if (numberReg.test(a[props]) && numberReg.test(b[props])) {
return (Number(a[props]) - Number(b[props])) * rev;
}
if (versionReg.test(a[props]) && versionReg.test(b[props])) {
return (
(a[props]
.split(".")
.map((v) => v.padStart(2, "0"))
.join("") -
b[props]
.split(".")
.map((v) => v.padStart(2, "0"))
.join("")) *
rev
);
}
if (zhReg.test(a[props]) && zhReg.test(b[props])) {
return (
a[props].localeCompare(b[props], "zh", {
numeric: true,
}) * rev
);
}
if (enReg.test(a[props]) && enReg.test(b[props])) {
return (
a[props].localeCompare(b[props], "en", {
numeric: true,
}) * rev
);
}
return mixedSort(a[props], b[props]) * rev;
}
function getCompareResultByDeep(
a,
b,
fieldConfigsIndex,
fieldConfigs,
mixedSort
) {
const _fieldConfigsIndex = fieldConfigsIndex + 1;
if (!fieldConfigs[_fieldConfigsIndex]) {
return 0;
}
const _props = fieldConfigs[_fieldConfigsIndex][0];
const _rev = fieldConfigs[_fieldConfigsIndex][1] === ORDER_PROP_ASC ? 1 : -1;
return getCompareResult(
a,
b,
_props,
_rev,
fieldConfigs,
_fieldConfigsIndex,
mixedSort
);
}
function sortHandle({ fieldConfigs = [], _sortConfig = {} }) {
const fieldConfigsIndex = 0;
if (!fieldConfigs[fieldConfigsIndex]) {
throw new Error("sortHandle的参数fieldConfigs不符合要求");
}
const props = fieldConfigs[fieldConfigsIndex][0];
const rev = fieldConfigs[fieldConfigsIndex][1] === ORDER_PROP_ASC ? 1 : -1;
const { sortWeight, sortMappingFn } = { ...sortConfig, ..._sortConfig };
const sortMapping = sortMappingFn(sortWeight);
const mixedSort = (a, b) => {
let _a = 99;
let _b = 99;
sortMapping.forEach((v) => {
if (v.reg.test(a)) _a = v.weight;
if (v.reg.test(b)) _b = v.weight;
});
return _a - _b;
};
return function (a, b) {
return getCompareResult(
a,
b,
props,
rev,
fieldConfigs,
fieldConfigsIndex,
mixedSort
);
};
}
function orderBy(
arr = [],
fieldConfigs = [["value", ORDER_PROP_ASC]],
_sortConfig = {}
) {
arr.sort(
sortHandle({
fieldConfigs,
_sortConfig,
})
);
}
const _arr = [
{ value: 4, date: "2020-05-06", version: "5.1.3" },
{ value: 5, date: "2020-05-01", version: "0.1.0" },
{ value: "(null)", date: "2020-05-01", version: "0.1.0" },
{ value: "--", date: "2020-05-01", version: "0.1.0" },
{ value: "2020-01-01", date: "2020-05-01", version: "0.1.0" },
{ value: "(10,20.1]", date: "2020-05-01", version: "0.1.0" },
{ value: "12你好", date: "2020-05-01", version: "0.1.0" },
{ value: "bdc", date: "2020-05-01", version: "0.1.0" },
{ value: 5, date: "2020-05-01", version: "0.1.0" },
{ value: "(null)", date: "2020-05-01", version: "0.1.0" },
{ value: "--", date: "2020-04-01", version: "0.1.0" },
{ value: "--", date: "2020-06-01", version: "0.1.0" },
{ value: "--", date: "2020-05-01", version: "0.1.0" },
{ value: "2020-01-02", date: "2020-05-01", version: "0.1.0" },
{ value: "(20.1,100]", date: "2020-05-01", version: "0.1.0" },
{ value: "啊好", date: "2020-05-01", version: "0.1.0" },
{ value: "ed", date: "2020-05-01", version: "0.1.0" },
{ value: "12.90.98", date: "2020-05-01", version: "0.1.0" },
{ value: "null", date: "2020-05-01", version: "0.1.0" },
];
const _arr2 = [];
for (let index = 0; index < 3; index++) {
_arr2.push(..._arr);
}
console.time("renderTime");
const config = {
sortWeight: {
zh: 0,
version: 1,
number: 2,
range: 3,
en: 4,
"--": 5,
date: 6,
null: 7,
"(null)": 8,
},
};
orderBy(
_arr2,
[
["value", ORDER_PROP_DESC],
["date", ORDER_PROP_DESC],
]
);
console.timeEnd("renderTime");
console.log(_arr2);
orderBy(
_arr2,
[
["value", ORDER_PROP_DESC],
["date", ORDER_PROP_DESC],
],
config
);
console.timeEnd("renderTime");
console.log(_arr2);
2023-07-27更新,上述版本拓展正则比较困难,所以改了一版
const _number = "number";
const _zh = "zh";
const _en = "en";
const _date = "date";
const _range = "range";
const _version = "version";
const _empty = "--";
const _null = "null";
const _null2 = "(null)";
const numberReg = [/^[-]?\d+(\.?\d)?\d*%?$/];
const versionReg = [/^(\d{1,2}\.){2,}\d{1,2}$/];
const rangeReg = [
/^[\(|\[]([-|+]?[∞|\d]+(\.?\d)?\d*){1},\s?(([-|+]?[∞|\d]+(\.?\d)?\d*){1})[\)|\]]$/,
];
const dateReg = [/^\d{4}([-\/])\d{2}(\1\d{2})?$/];
const enReg = [/^(?![0-9]*$)[a-zA-Z0-9\.\s-_]+$/];
const zhReg = [/[\u4e00-\u9fa5]/];
const emptyReg = [/^--$/];
const NULL = ["null", "(null)"];
const ORDER_PROP_ASC = "asc";
const ORDER_PROP_DESC = "desc";
function regularOk(regs = [], value) {
return regs.some((v) => v.test(value));
}
const sortConfig = {
sortWeight: {
[_number]: 1,
[_zh]: 2,
[_en]: 3,
[_date]: 4,
[_range]: 5,
[_version]: 6,
[_empty]: 100,
[_null]: 101,
[_null2]: 102,
},
sortMappingFn(sortWeight) {
const _mapping = [
{
reg: emptyReg,
weight: sortWeight[_empty],
},
{
reg: numberReg,
weight: sortWeight[_number],
},
{
reg: versionReg,
weight: sortWeight[_version],
},
{
reg: rangeReg,
weight: sortWeight[_range],
},
{
reg: dateReg,
weight: sortWeight[_date],
},
{
reg: enReg,
weight: sortWeight[_en],
},
{
reg: zhReg,
weight: sortWeight[_zh],
},
];
return _mapping;
},
};
function getCompareResult(
a,
b,
props,
rev,
fieldConfigs = [],
fieldConfigsIndex = 0,
mixedSort
) {
if (NULL.includes(a[props])) {
return 1 * rev;
}
if (NULL.includes(b[props])) {
return -1 * rev;
}
if (a[props] === b[props]) {
const _fieldConfigsIndex = fieldConfigsIndex + 1;
if (!fieldConfigs[_fieldConfigsIndex]) {
return 0;
}
const _props = fieldConfigs[_fieldConfigsIndex][0];
const _rev =
fieldConfigs[_fieldConfigsIndex][1] === ORDER_PROP_ASC ? 1 : -1;
return getCompareResult(
a,
b,
_props,
_rev,
fieldConfigs,
_fieldConfigsIndex,
mixedSort
);
}
const fieldConfigsRow = fieldConfigs[fieldConfigsIndex];
if (fieldConfigsRow.length === 3) {
const { config, sort } = fieldConfigsRow[2];
return sort(a[props], b[props], config) * rev;
}
if (regularOk(dateReg, a[props]) && regularOk(dateReg, b[props])) {
return (Date.parse(a[props]) - Date.parse(b[props])) * rev;
}
if (regularOk(rangeReg, a[props]) && regularOk(rangeReg, b[props])) {
if (a[props].includes("-∞")) return -1 * rev;
if (a[props].includes("+∞")) return 1 * rev;
if (b[props].includes("-∞")) return 1 * rev;
if (b[props].includes("+∞")) return -1 * rev;
const n1 = a[props].slice(a[props].indexOf(",") + 1, a[props].length - 1);
const n2 = b[props].slice(b[props].indexOf(",") + 1, b[props].length - 1);
return (Number(n1) - Number(n2)) * rev;
}
if (regularOk(numberReg, a[props]) && regularOk(numberReg, b[props])) {
const _a = (a[props] + "").endsWith("%")
? a[props].slice(0, a[props].length - 1)
: a[props];
const _b = (b[props] + "").endsWith("%")
? b[props].slice(0, b[props].length - 1)
: b[props];
return (_a - _b) * rev;
}
if (regularOk(versionReg, a[props]) && regularOk(versionReg, b[props])) {
return (
(a[props]
.split(".")
.map((v) => v.padStart(2, "0"))
.join("") -
b[props]
.split(".")
.map((v) => v.padStart(2, "0"))
.join("")) *
rev
);
}
if (regularOk(zhReg, a[props]) && regularOk(zhReg, b[props])) {
return (
a[props].localeCompare(b[props], "zh", {
numeric: true,
}) * rev
);
}
if (regularOk(enReg, a[props]) && regularOk(enReg, b[props])) {
return (
a[props].localeCompare(b[props], "en", {
numeric: true,
}) * rev
);
}
return mixedSort(a[props], b[props]) * rev;
}
function sortHandle({ fieldConfigs = [], _sortConfig = {} }) {
const fieldConfigsIndex = 0;
if (!fieldConfigs[fieldConfigsIndex]) {
throw new Error("sortHandle的参数fieldConfigs不符合要求");
}
const props = fieldConfigs[fieldConfigsIndex][0];
const rev = fieldConfigs[fieldConfigsIndex][1] === ORDER_PROP_ASC ? 1 : -1;
const { sortWeight, sortMappingFn } = { ...sortConfig, ..._sortConfig };
const sortMapping = sortMappingFn(sortWeight);
const mixedSort = (a, b) => {
let _a = 99;
let _b = 99;
sortMapping.forEach((v) => {
if (regularOk(v.reg, a)) _a = v.weight;
if (regularOk(v.reg, b)) _b = v.weight;
});
return _a - _b;
};
return function (a, b) {
return getCompareResult(
a,
b,
props,
rev,
fieldConfigs,
fieldConfigsIndex,
mixedSort
);
};
}
function sortPlusUtil(
arr = [],
fieldConfigs = [["value", ORDER_PROP_ASC]],
_sortConfig = {}
) {
arr.sort(
sortHandle({
fieldConfigs,
_sortConfig,
})
);
}
const arr = [
{ name: "a", age: 100 },
{ name: "a", age: 2 },
{ name: "a", age: 10 },
];
sortPlusUtil(arr, [
["name", "desc"],
["age", "desc"],
]);
console.log(arr);