Sort/order 由两个条件(名称序列和日期)组成的字符串数组- JavaScript
Sort/order a string array by two conditions (name sequence and date)- JavaScript
尝试 sort/order 这个字符串数组时遇到一些问题。响应中返回的文件名有数千个,下面以 10 个为例。
array = [
'ORDERHEADER_010122.arc',
'ORDERITEM_010122.arc',
'ORDERDETAIL_010122.arc',
'ORDERDETAIL_010222.arc',
'ORDERDETAIL_010322.arc',
'ORDERHEADER_010222.arc',
'ORDERHEADER_010322.arc',
'ORDERHEADER_010422.arc',
'ORDERITEM_010222.arc',
'ORDERDETAIL_010422.arc'
];
一个简单的 array.sort()
解决了一半的问题,因为它将按字母顺序排列字符串并固有地对日期进行排序。
我需要的是排序的“顺序”顺序以及日期顺序。所以 prioSequence = ['ORDERHEADER', 'ORDERDETAIL', 'ORDERITEM'];
将是我想要看到的序列。
预期输出为:
array = [
'ORDERHEADER_010122.arc',
'ORDERDETAIL_010122.arc',
'ORDERITEM_010122.arc',
'ORDERHEADER_010222.arc',
'ORDERDETAIL_010222.arc',
'ORDERITEM_010222.arc',
'ORDERHEADER_010322.arc',
'ORDERDETAIL_010322.arc',
'ORDERHEADER_010422.arc',
'ORDERDETAIL_010422.arc'
];
任何 help/guidance 将不胜感激!谢谢!
在字符串前加上确定排序的部分,即 yymmdd 和“ORDER”字符串中的 2 个字母,事实证明,当您选择这些单词的第 7 和第 8 个字母时(EA、ET、TE ), 它们将被正确排序。然后在对项目进行排序后,再次删除该前缀。
结果如下:
let array = [
'ORDERHEADER_010122.arc',
'ORDERITEM_010122.arc',
'ORDERDETAIL_010122.arc',
'ORDERDETAIL_010222.arc',
'ORDERDETAIL_010322.arc',
'ORDERHEADER_010222.arc',
'ORDERHEADER_010322.arc',
'ORDERHEADER_010422.arc',
'ORDERITEM_010222.arc',
'ORDERDETAIL_010422.arc'
];
let sorted = array.map(item =>
item.replace(/ORDER.(..).*?_(..)(..)(..).*/g, "") + item
).sort().map(s => s.slice(8));
console.log(sorted);
扩展它
如果您有更多 prefix-words 个要控制顺序,请按预期顺序创建一个数组。该解决方案然后将该数组转换为查找映射(为给定单词提供 4 个字符的序列号)。对 replace
的调用需要一个回调参数,它将进行查找并为该序列添加前缀。这是相关代码:
let array = [
'ORDERHEADER_010122.arc',
'ORDERITEM_010122.arc',
'ORDERDETAIL_010122.arc',
'ORDERDETAIL_010222.arc',
'ORDERDETAIL_010322.arc',
'ORDERHEADER_010222.arc',
'ORDERHEADER_010322.arc',
'ORDERHEADER_010422.arc',
'ORDERITEM_010222.arc',
'ORDERDETAIL_010422.arc'
];
let priorities = [
'ORDERHEADER',
'ORDERDETAIL',
'ORDERITEM',
];
// Map the priority array to an object for faster look-up
let priMap = Object.fromEntries(priorities.map((word, i) =>
[word, ("000" + i).slice(-4)]
));
let sorted = array.map(item =>
item.replace(/(.*?)_(..)(..)(..).*/g, (all, word, dd, mm, yy) =>
yy + mm + dd + (priMap[word] ?? "----") + all
)
).sort().map(s => s.slice(10));
console.log(sorted);
您必须为排序方法调用定义自定义比较函数。而且,该方法应该首先比较日期,然后(如果日期相同)根据您的要求订购前缀
这是我的例子
const order = new Map() // one can use plain Array + Array#indexOf later on
.set('ORDERHEADER', 0)
.set('ORDERDETAIL', 1)
.set('ORDERITEM', 2)
const compareFn = (a, b) => {
const [a1, a2] = a.split('_')
const [b1, b2] = b.split('_')
const r2 = a2.localeCompare(b2) // TODO: re-write to date comparison a2 vs b2
if (r2 !== 0) return r2
return order.get(a1) - order.get(b1) // or Array#indexOf as mentioned above
}
// usage
array.sort(compareFn)
尝试 sort/order 这个字符串数组时遇到一些问题。响应中返回的文件名有数千个,下面以 10 个为例。
array = [
'ORDERHEADER_010122.arc',
'ORDERITEM_010122.arc',
'ORDERDETAIL_010122.arc',
'ORDERDETAIL_010222.arc',
'ORDERDETAIL_010322.arc',
'ORDERHEADER_010222.arc',
'ORDERHEADER_010322.arc',
'ORDERHEADER_010422.arc',
'ORDERITEM_010222.arc',
'ORDERDETAIL_010422.arc'
];
一个简单的 array.sort()
解决了一半的问题,因为它将按字母顺序排列字符串并固有地对日期进行排序。
我需要的是排序的“顺序”顺序以及日期顺序。所以 prioSequence = ['ORDERHEADER', 'ORDERDETAIL', 'ORDERITEM'];
将是我想要看到的序列。
预期输出为:
array = [
'ORDERHEADER_010122.arc',
'ORDERDETAIL_010122.arc',
'ORDERITEM_010122.arc',
'ORDERHEADER_010222.arc',
'ORDERDETAIL_010222.arc',
'ORDERITEM_010222.arc',
'ORDERHEADER_010322.arc',
'ORDERDETAIL_010322.arc',
'ORDERHEADER_010422.arc',
'ORDERDETAIL_010422.arc'
];
任何 help/guidance 将不胜感激!谢谢!
在字符串前加上确定排序的部分,即 yymmdd 和“ORDER”字符串中的 2 个字母,事实证明,当您选择这些单词的第 7 和第 8 个字母时(EA、ET、TE ), 它们将被正确排序。然后在对项目进行排序后,再次删除该前缀。
结果如下:
let array = [
'ORDERHEADER_010122.arc',
'ORDERITEM_010122.arc',
'ORDERDETAIL_010122.arc',
'ORDERDETAIL_010222.arc',
'ORDERDETAIL_010322.arc',
'ORDERHEADER_010222.arc',
'ORDERHEADER_010322.arc',
'ORDERHEADER_010422.arc',
'ORDERITEM_010222.arc',
'ORDERDETAIL_010422.arc'
];
let sorted = array.map(item =>
item.replace(/ORDER.(..).*?_(..)(..)(..).*/g, "") + item
).sort().map(s => s.slice(8));
console.log(sorted);
扩展它
如果您有更多 prefix-words 个要控制顺序,请按预期顺序创建一个数组。该解决方案然后将该数组转换为查找映射(为给定单词提供 4 个字符的序列号)。对 replace
的调用需要一个回调参数,它将进行查找并为该序列添加前缀。这是相关代码:
let array = [
'ORDERHEADER_010122.arc',
'ORDERITEM_010122.arc',
'ORDERDETAIL_010122.arc',
'ORDERDETAIL_010222.arc',
'ORDERDETAIL_010322.arc',
'ORDERHEADER_010222.arc',
'ORDERHEADER_010322.arc',
'ORDERHEADER_010422.arc',
'ORDERITEM_010222.arc',
'ORDERDETAIL_010422.arc'
];
let priorities = [
'ORDERHEADER',
'ORDERDETAIL',
'ORDERITEM',
];
// Map the priority array to an object for faster look-up
let priMap = Object.fromEntries(priorities.map((word, i) =>
[word, ("000" + i).slice(-4)]
));
let sorted = array.map(item =>
item.replace(/(.*?)_(..)(..)(..).*/g, (all, word, dd, mm, yy) =>
yy + mm + dd + (priMap[word] ?? "----") + all
)
).sort().map(s => s.slice(10));
console.log(sorted);
您必须为排序方法调用定义自定义比较函数。而且,该方法应该首先比较日期,然后(如果日期相同)根据您的要求订购前缀
这是我的例子
const order = new Map() // one can use plain Array + Array#indexOf later on
.set('ORDERHEADER', 0)
.set('ORDERDETAIL', 1)
.set('ORDERITEM', 2)
const compareFn = (a, b) => {
const [a1, a2] = a.split('_')
const [b1, b2] = b.split('_')
const r2 = a2.localeCompare(b2) // TODO: re-write to date comparison a2 vs b2
if (r2 !== 0) return r2
return order.get(a1) - order.get(b1) // or Array#indexOf as mentioned above
}
// usage
array.sort(compareFn)