我想对王室名称进行排序。对字母表的第一个偏好。如果两个名字相同,那么我想按罗马数字排序。例如,输入为:King III,King II,Queen IX。 (因为前2个字符串相同,所以需要按照附加的罗马数字进行排序)所以预期输出:King II,King III,Queen IX。
我尝试在罗马地图中存储罗马数字并编写一个函数,将给定数组中的罗马数字替换为King 2,King 3,Queen 9,然后尝试排序,但无法正确实现。有人可以帮我这个吗?
function romanToNum(roman) {
if (roman === "") return 0;
if (roman.startsWith("L")) return 50 + romanToNum(roman.substr(1));
if (roman.startsWith("XL")) return 40 + romanToNum(roman.substr(2));
if (roman.startsWith("X")) return 10 + romanToNum(roman.substr(1));
if (roman.startsWith("IX")) return 9 + romanToNum(roman.substr(2));
if (roman.startsWith("V")) return 5 + romanToNum(roman.substr(1));
if (roman.startsWith("IV")) return 4 + romanToNum(roman.substr(2));
if (roman.startsWith("I")) return 1 + romanToNum(roman.substr(1));
return 0;
}
console.log(
["King III", "King II", "Queen IX"]
.map((n) => ({name: n, num: romanToNum(n.split(" ").pop())}))
.sort((a, b) => (a.num - b.num))
.map(({name, num}) => name)
);
romanToNum
功能改编自this answer。首先将数组映射到{name, num}
对象,然后在num
上排序,然后仅转换回name
s。
您可以拆分字符串并使用sorting with map,同时将该元素的每个元素与另一个元素的每个元素进行比较。如果两个元素都是数字,则取差异,否则返回localeCompare
的结果。
function customSort(data, 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.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 = ['King III', 'King II', 'Queen IX'];
console.log('sorted array asc', customSort(arr));
console.log('sorted array desc', customSort(arr, 'desc'));
console.log('original array', arr);
.as-console-wrapper { max-height: 100% !important; top: 0; }
使用您自己的转换表来获取罗马数字的十进制值,而不是使用正确的回调进行简单排序
var romanNumberToDec = {
"I" : 1, "II" : 2, "III" : 3, "IV" : 4, "V" : 5,
"VI" : 6, "VII" : 7, "VIII" : 8, "IX" : 9, "X" : 10
}
ES6console与桌子
如果这就是你需要处理的全部内容
但如果你需要更通用的方式 - from selftaughtjs -
function fromRoman(str) {
var result = 0;
// the result is now a number, not a string
var decimal = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
var roman = ["M", "CM","D","CD","C", "XC", "L", "XL", "X","IX","V","IV","I"];
for (var i = 0;i<=decimal.length;i++) {
while (str.indexOf(roman[i]) === 0){
result += decimal[i];
str = str.replace(roman[i],'');
}
}
return result;
}
var arrayObj = [ "King III", "King II", "Queen IX"];
function mySort() {
arrayObj.sort( (a, b)=> {
let aNum = a.substr(a.lastIndexOf(" ") + 1, a.length);
let bNum = b.substr(b.lastIndexOf(" ") + 1, b.length);
// return romanNumberToDec[aNum] - romanNumberToDec[bNum];
return fromRoman(aNum) - fromRoman(bNum);
});
console.log(arrayObj);
};
mySort();
ES6console的通用方式