我正在寻找一种最简单的方法来对由数字和文本以及这些组合组成的数组进行排序。
例如:
'123asd'
'19asd'
'12345asd'
'asd123'
'asd12'
变成
'19asd'
'123asd'
'12345asd'
'asd12'
'asd123'
这将与我在这里提出的另一个问题的解决方案结合使用。
排序函数本身是有效的,我需要一个能够说明'19asd'比'123asd'小的函数。
我正在用JavaScript编写此代码。
我正在寻找一个自然排序的函数。
我正在寻找一种最简单的方法来对由数字和文本以及这些组合组成的数组进行排序。
例如:
'123asd'
'19asd'
'12345asd'
'asd123'
'asd12'
变成
'19asd'
'123asd'
'12345asd'
'asd12'
'asd123'
这将与我在这里提出的另一个问题的解决方案结合使用。
排序函数本身是有效的,我需要一个能够说明'19asd'比'123asd'小的函数。
我正在用JavaScript编写此代码。
我正在寻找一个自然排序的函数。
numeric:true
选项,它会智能地识别数字。您可以使用sensitivity:'base'
进行不区分大小写的比较。已在Chrome、Firefox和Internet Explorer 11中测试过。
这是一个例子,它返回1
,表示10在2之后:
'10'.localeCompare('2', undefined, {numeric: true, sensitivity: 'base'})
在对大量字符串进行排序时,该文章指出:
如果要比较大量的字符串,例如对大型数组进行排序,则最好创建一个 Intl.Collator 对象并使用其 compare 属性提供的函数。
var collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
var myArray = ['1_Document', '11_Document', '2_Document'];
console.log(myArray.sort(collator.compare));
如果你有一个对象数组,你可以这样做:
myArrayObjects = myArrayObjects.sort(function(a, b) {
return a.name.localeCompare(b.name, undefined, {
numeric: true,
sensitivity: 'base'
});
});
var myArrayObjects = [{
"id": 1,
"name": "1 example"
},
{
"id": 2,
"name": "100 example"
},
{
"id": 3,
"name": "12 example"
},
{
"id": 4,
"name": "5 example"
},
]
myArrayObjects = myArrayObjects.sort(function(a, b) {
return a.name.localeCompare(b.name, undefined, {
numeric: true,
sensitivity: 'base'
});
});
console.log(myArrayObjects);
function naturalSorter(as, bs){
var a, b, a1, b1, i= 0, n, L,
rx=/(\.\d+)|(\d+(\.\d+)?)|([^\d.]+)|(\.\D+)|(\.$)/g;
if(as=== bs) return 0;
a= as.toLowerCase().match(rx);
b= bs.toLowerCase().match(rx);
L= a.length;
while(i<L){
if(!b[i]) return 1;
a1= a[i],
b1= b[i++];
if(a1!== b1){
n= a1-b1;
if(!isNaN(n)) return n;
return a1>b1? 1:-1;
}
}
return b[i]? -1:0;
}
如果要快速排序一个数组,可以在排序之前先调整好数组的格式,这样你只需要在排序时进行一次小写转换和正则表达式操作,而不是在每一步中都进行。
function naturalSort(ar, index){
var L= ar.length, i, who, next,
isi= typeof index== 'number',
rx= /(\.\d+)|(\d+(\.\d+)?)|([^\d.]+)|(\.(\D+|$))/g;
function nSort(aa, bb){
var a= aa[0], b= bb[0], a1, b1, i= 0, n, L= a.length;
while(i<L){
if(!b[i]) return 1;
a1= a[i];
b1= b[i++];
if(a1!== b1){
n= a1-b1;
if(!isNaN(n)) return n;
return a1>b1? 1: -1;
}
}
return b[i]!= undefined? -1: 0;
}
for(i= 0; i<L; i++){
who= ar[i];
next= isi? ar[i][index] || '': who;
ar[i]= [String(next).toLowerCase().match(rx), who];
}
ar.sort(nSort);
for(i= 0; i<L; i++){
ar[i]= ar[i][1];
}
}
String.prototype.tlc()
是什么?这是你自己的代码还是从其他地方获取的?如果是后者,请提供链接。 - Andy E想象一个数字零填充函数n => n.padStart(8, "0")
,它接受任何数字并对其进行填充,例如:
这个函数可以用来帮助排序字符串"19"
,使其出现在字符串"123"
之前。
我们添加一个正则表达式/\d+/g
,创建自然扩展函数str => str.replace(/\d+/g, n => n.padStart(8, "0"))
,该函数仅在字符串中查找数字部分并进行填充,例如:
现在,我们可以使用这个自然扩展函数来帮助实现自然顺序排序:
const list = [
"123asd",
"19asd",
"12345asd",
"asd123",
"asd12"
];
const ne = str => str.replace(/\d+/g, n => n.padStart(8, "0"));
const nc = (a,b) => ne(a).localeCompare(ne(b));
console.log(list.map(ne).sort()); // intermediate values
console.log(list.sort(nc)); // result
list.map(ne).sort()
展示了 ne
自然扩展函数的中间结果。它仅在字符串的数字部分上实现数字零填充,并保留字母组件不变。[
"00000019asd",
"00000123asd",
"00012345asd",
"asd00000012",
"asd00000123"
]
nc
,它被实现为(a,b) => ne(a).localeCompare(ne(b))
并在list.sort(nc)
中使用,以便正确排序。[
"19asd",
"123asd",
"12345asd",
"asd12",
"asd123"
]
import { orderBy } from 'natural-orderby'
const unordered = [
'123asd',
'19asd',
'12345asd',
'asd123',
'asd12'
]
const ordered = orderBy(unordered)
// [ '19asd',
// '123asd',
// '12345asd',
// 'asd12',
// 'asd123' ]
它不仅可以对字符串数组进行排序,还可以按照对象数组中某个键的值进行排序。它还可以自动识别和排序货币、日期、货币等字符串,以及其他一些内容。
令人惊讶的是,当使用gzip压缩后,它的大小只有1.6 kB。
在 kennebec 的回答 基础上,使用 Brian Huisman 和 David koelle 创建的代码,这里是一个修改后的原型排序,用于数组对象:
//Usage: unsortedArrayOfObjects.alphaNumObjectSort("name");
//Test Case: var unsortedArrayOfObjects = [{name: "a1"}, {name: "a2"}, {name: "a3"}, {name: "a10"}, {name: "a5"}, {name: "a13"}, {name: "a20"}, {name: "a8"}, {name: "8b7uaf5q11"}];
//Sorted: [{name: "8b7uaf5q11"}, {name: "a1"}, {name: "a2"}, {name: "a3"}, {name: "a5"}, {name: "a8"}, {name: "a10"}, {name: "a13"}, {name: "a20"}]
// **Sorts in place**
Array.prototype.alphaNumObjectSort = function(attribute, caseInsensitive) {
for (var z = 0, t; t = this[z]; z++) {
this[z].sortArray = new Array();
var x = 0, y = -1, n = 0, i, j;
while (i = (j = t[attribute].charAt(x++)).charCodeAt(0)) {
var m = (i == 46 || (i >=48 && i <= 57));
if (m !== n) {
this[z].sortArray[++y] = "";
n = m;
}
this[z].sortArray[y] += j;
}
}
this.sort(function(a, b) {
for (var x = 0, aa, bb; (aa = a.sortArray[x]) && (bb = b.sortArray[x]); x++) {
if (caseInsensitive) {
aa = aa.toLowerCase();
bb = bb.toLowerCase();
}
if (aa !== bb) {
var c = Number(aa), d = Number(bb);
if (c == aa && d == bb) {
return c - d;
} else {
return (aa > bb) ? 1 : -1;
}
}
}
return a.sortArray.length - b.sortArray.length;
});
for (var z = 0; z < this.length; z++) {
// Here we're deleting the unused "sortArray" instead of joining the string parts
delete this[z]["sortArray"];
}
}
const orderBy = orders => (a, b) => {
const sortDirection = { asc: 1, desc: -1 };
const sortCollator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });
const totalOrders = orders.length;
for (let index = 0; index < totalOrders; index++) {
const { property, direction = 'desc' } = orders[index];
const directionInt = sortDirection[direction];
const compare = sortCollator.compare(a[property], b[property]);
if (compare < 0) return directionInt;
if (compare > 0) return -directionInt;
}
return 0;
};
// Example:
const unsorted = [
{ name: 'Bananas', count: 1 },
{ name: 'Apples', count: 3 },
{ name: 'Bananas', count: 3 },
{ name: 'bananas', count: 2 },
];
const sorted = unsorted.sort(orderBy([{ property: 'name' }, { property: 'count', direction: 'asc' }]));
console.log(sorted);