I would like to sort royal names. First Preference to the alphabet. If both names are same then I would like to sort by the roman numeral. For Example if input is : King III, King II, Queen IX. (as 1st 2 strings are same they need to be sorted by their appended roman numeral) So Expected output : King II, King III, Queen IX.
I tried storing roman numerals in a hashmap and writing a function that replaces roman numerals in given array to King 2, King 3, Queen 9 and then tried sorting but was not able to implement correctly. Could anyone kindly help me with this?
I would like to sort royal names. First Preference to the alphabet. If both names are same then I would like to sort by the roman numeral. For Example if input is : King III, King II, Queen IX. (as 1st 2 strings are same they need to be sorted by their appended roman numeral) So Expected output : King II, King III, Queen IX.
I tried storing roman numerals in a hashmap and writing a function that replaces roman numerals in given array to King 2, King 3, Queen 9 and then tried sorting but was not able to implement correctly. Could anyone kindly help me with this?
Share Improve this question edited Mar 5, 2018 at 0:53 Sai asked Feb 3, 2018 at 19:40 Sai Sai 2851 gold badge4 silver badges12 bronze badges 1- 3 did you research anything or did you already try anything? – messerbill Commented Feb 3, 2018 at 19:52
3 Answers
Reset to default 6
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
function adapted from this answer. The array is first mapped into {name, num}
objects, then sorted on num
, then converted back to name
s only.
You could split the string and use sorting with map, while paring each element of the one with each element of the other one. if both elements are numbers, take the difference, otherwise return the result of localeCompare
.
function customSort(data, order) {
function isNumber(v) {
return (+v).toString() === v;
}
function isRoman(s) {
// http://stackoverflow./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; }
use your own convert table to get the decimal value of the roman numbers, than a simple sort with the proper callback
var romanNumberToDec = {
"I" : 1, "II" : 2, "III" : 3, "IV" : 4, "V" : 5,
"VI" : 6, "VII" : 7, "VIII" : 8, "IX" : 9, "X" : 10
}
ES6console with the table
if thats all you need to deal with
but if you need a more generic way - 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 the generic way
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744693538a4588355.html
评论列表(0条)