我尝试了典型的排序函数并检查了项目是否为字符串。但是我得到一个很奇怪的输出。试过很多不同的方法
var arr = [{section: '12.2.a'},
{section: '12.2.b.iii'},
{section: '12.2.c'},
{section: '12'},
{section: '12A'},
{section: '12.3.b'},
{section: '12.3.c'},
{section: 'Q2'},
{section: 'Q32'},
{section: 'Q6'},
{section: 'Q5'}]
var arr2 = arr.sort(function(a, b) {
var nums1 = a.section.split(".");
var nums2 = b.section.split(".");
for (var i = 0; i < nums1.length; i++) {
if (nums2[i]) {
if (nums1[i] !== nums2[i]) {
if (isNaN(parseInt(nums1[i])) && isNaN(parseInt(nums2[i]))) {
return nums1[i].localeCompare(nums2[i]);
}
return parseInt(nums1[i]) - parseInt(nums2[i]);
}
} else {
return 1;
}
}
return -1;
});
我应该使用localeCompare还是可以不使用?希望输出为:
[
{section: '12'},
{section: '12A'},
{section: '12.2.a'},
{section: '12.2.b.iii'},
{section: '12.2.c'},
{section: '12.3.b'},
{section: '12.3.c'},
{section: 'Q2'},
{section: 'Q6'},
{section: 'Q5'}
{section: 'Q32'}]
非常感谢您的建议
我提出一个完全不同的方法。我们将修改您的字符串,直到它们可以通过localeCompare
方法如下:
// "12" sorts before "2", prefixing to "12" and "02" fixes this
// (length should be bigger than your largest nr)
var makeLength5 = prefixWithZero.bind(null, 5);
// This function generates a string that is sortable by localeCompare
var toSortableString = function(obj) {
return obj.section
.replace(/./g, "z") // Places `12A` before `12.` but after `12`
.replace(/d+/g, makeLength5); // Makes every number the same length
};
var arr = [{section:"12.2.a"},{section:"12.2.b.iii"},{section:"12.2.c"},{section:"12"},{section:"12A"},{section:"12.3.b"},{section:"12.3.c"},{section:"Q2"},{section:"Q32"},{section:"Q6"},{section:"Q5"}];
var arr2 = arr.sort(function(a, b) {
return toSortableString(a).localeCompare(toSortableString(b));
});
console.log(JSON.stringify(arr2.map(function(s){ return s.section; }), null, 2));
// Helper methods
function prefixWithZero(length, str) {
while (str.length < length) {
str = "0" + str;
}
return str;
};
您可以拆分字符串并使用map排序,同时将其中的每个元素与另一个中的每个元素进行比较。如果两个元素都是数字,取差值,否则返回localeCompare
的结果。
附加功能:用罗马数字排序。
function customSort(data, key, order) {
function isNumber(v) {
return (+v).toString() === v;
}
function isRoman(s) {
// http://stackoverflow.com/a/267405/1447675
return /^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/i.test(s);
}
function parseRoman(s) {
var val = { M: 1000, D: 500, C: 100, L: 50, X: 10, V: 5, I: 1 };
return s.toUpperCase().split('').reduce(function (r, a, i, aa) {
return val[a] < val[aa[i + 1]] ? r - val[a] : r + val[a];
}, 0);
}
var sort = {
asc: function (a, b) {
var i = 0,
l = Math.min(a.value.length, b.value.length);
while (i < l && a.value[i] === b.value[i]) {
i++;
}
if (i === l) {
return a.value.length - b.value.length;
}
if (isNumber(a.value[i]) && isNumber(b.value[i])) {
return a.value[i] - b.value[i];
}
if (isRoman(a.value[i]) && isRoman(b.value[i])) {
return parseRoman(a.value[i]) - parseRoman(b.value[i]);
}
return a.value[i].localeCompare(b.value[i]);
},
desc: function (a, b) {
return sort.asc(b, a);
}
},
mapped = data.map(function (el, i) {
var string = el[key].replace(/d(?=[a-z])|[a-z](?=.)/gi, '$&. .'),
regex = /(d+)|([^0-9.]+)/g,
m,
parts = [];
while ((m = regex.exec(string)) !== null) {
parts.push(m[0]);
}
return { index: i, value: parts, o: el, string: string };
});
mapped.sort(sort[order] || sort.asc);
return mapped.map(function (el) {
return data[el.index];
});
}
var arr = [{ section: '12.2.a' }, { section: '12.2.b.viii' }, { section: '12.2.b.xi' }, { section: '12.2.b.x' }, { section: '12.2.b.ix' }, { section: '12.2.b.vii' }, { section: '12.2.b.vi' }, { section: '12.2.b.iv' }, { section: '12.2.b.v' }, { section: '12.2.b.ii' }, { section: '12.2.b.iii' }, { section: '12.2.b.i' }, { section: '12.2.b.iii' }, { section: '12.2.c' }, { section: '12' }, { section: '12A' }, { section: '12.3.b' }, { section: '12.3.c' }, { section: 'Q2' }, { section: 'Q32' }, { section: 'Q6' }, { section: 'Q5' }, { section: 'Q.10' }, { section: 'Q.1' }, { section: 'Q.2' }];
console.log('sorted array asc', customSort(arr, 'section'));
console.log('sorted array desc', customSort(arr, 'section', 'desc'));
console.log('original array', arr);
.as-console-wrapper { max-height: 100% !important; top: 0; }