JavaScript

[checkio] Roman Numerals

お題は引数として与えられるアラビア表記の数値を、ローマ表記の数値に直すというもの。
例)
89 → LXXXIX
290 → CCXC

今回は無念としか言いようのないコードが出来上がった・・・!!

自分の回答

function romanNumerals(number) {

    //variables
    let answer = "";
    let bsNum = [1000, 100, 10, 1];
    let count = 0;

    for (let i of bsNum) {
        count = 0;
        while (number>=i) {
            number -= i;
            count += 1;
        }
        if (count) {
            romanMaker(i,count);
        }
    }

    //identifier
    function romanMaker(num1, num2) {
        let a="", b="", c="";
        switch (num1) {
            case 1000:
            a = "M";
            break;

            case 100:
            a = "C";
            b = "D";
            c = "M";
            break;

            case 10:
            a = "X";
            b = "L";
            c = "C";
            break;

            case 1:
            a = "I";
            b = "V";
            c = "X";
            break;
        }
        switch (num2) {
            case 1:
            answer += a;
            break;

            case 2:
            answer += a+a;
            break;

            case 3:
            answer += a+a+a;
            break;

            case 4:
            answer += a+b;
            break;

            case 5:
            answer += b;
            break;

            case 6:
            answer += b+a;
            break;

            case 7:
            answer += b+a+a;
            break;

            case 8:
            answer += b+a+a+a;
            break;

            case 9:
            answer += a+c;
            break;
        }
    }
    return answer;
}

これはひどい。でもこれしか浮かばなかった。4とか9のケースが曲者。

すごいかいとう

function romanNumerals(number) {
    var out = ""
    var units = [[1000,'M'], [900,'CM'], [500,'D'], [400,'CD'], [100,'C'], [90,'XC'],  [50,'L'],  [40,'XL'],  [10,'X'],  [9,'IX'],  [5,'V'],  [4,'IV'],  [1,'I']]
    units.forEach(function(unit) {
        while(number >= unit[0]) {
            number -= unit[0]
            out += unit[1]
    }})
    return out
}

行数が圧倒的に少ない。でも結局ある程度パターンを表記しなきゃいけないことは変わらないのか。
3行目のunits変数で見なければいけない数値とそれのローマ表記の数値のペアを連想配列として定義。
4-8行ではまずforEachを使って、一つずつ配列を取り出し、値を引き算しつつ、リターンの文字列に対応するものを加えていく。スマート。

学び

switchの条件式とcaseについて

  • switchにてbreakを置き忘れると、caseに合致した箇所以降の処理をcaseに合致しているか関係なく行うという仕様らしい。

break を置かなければ、スクリプトは基準を満たす case から実行され、その後の case も基準を満たすかに関係なく実行されます。
参考:switch構文 - MDN

以下で両方のlogが出力されてしまうのはそのため。最初は部分一致的な仕様かと思ったけど。

switch (10) {
    case 10:
    console.log("10ですね");

    case 1:
    console.log("1やな");
}
//output
10ですね
1ですね

Array.forEach()

  • Arrayの配列から一つずつ値を取り出して、callback関数を呼び出す。callbackの引数には取り出した処理中の要素と配列内でのインデックスを指定できる。

反省

一応bsNumの部分はconstで定義できるので、その方がよかったかも。