用点、字母、数字对对象数组进行排序。我能够按数字排序,但混合值很困难。不确定是不是可以做对
Posted
技术标签:
【中文标题】用点、字母、数字对对象数组进行排序。我能够按数字排序,但混合值很困难。不确定是不是可以做对【英文标题】:Sort array of objects with dots, letters, numbers. I was able to sort by numbers, but mixed values are difficult. Not sure if possible to do it right用点、字母、数字对对象数组进行排序。我能够按数字排序,但混合值很困难。不确定是否可以做对 【发布时间】:2017-03-02 04:37:44 【问题描述】:我尝试了典型的排序功能并检查项目是否为字符串。但我得到一个非常奇怪的输出。尝试了多种不同的方法。
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']
非常感谢任何建议
【问题讨论】:
【参考方案1】:您可以拆分字符串并使用sorting with map,同时将一个字符串的每个元素与另一个字符串的每个元素进行比较。如果两个元素都是数字,则取差,否则返回localeCompare
的结果。
奖励:按罗马数字排序。
function customSort(data, key, order)
function isNumber(v)
return (+v).toString() === v;
function isRoman(s)
// http://***.com/a/267405/1447675
return /^M0,4(CM|CD|D?C0,3)(XC|XL|L?X0,3)(IX|IV|V?I0,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;
【讨论】:
【参考方案2】:我提出了一种完全不同的方法。 我们将修改您的字符串,直到它们可以按 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;
;
【讨论】:
非常感谢!这太棒了! 免责声明:只有出现在字符串末尾且小于 IX 的罗马数字才会正确排序 我想用这个答案展示的是,一个快速的测试驱动实现可能会让你用更简单的代码完成 99% 的工作。不确定您是否可以在生产代码中摆脱它,但这是一个有趣的练习。特别是如果像您的问题一样,您不是将需求作为规范列表而是作为测试数据的集合(“从 this 到 that”)。以上是关于用点、字母、数字对对象数组进行排序。我能够按数字排序,但混合值很困难。不确定是不是可以做对的主要内容,如果未能解决你的问题,请参考以下文章