最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

arrays - Sorting Royal Names using javascript - Stack Overflow

programmeradmin0浏览0评论

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
Add a ment  | 

3 Answers 3

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 names 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

发布评论

评论列表(0)

  1. 暂无评论