JavaScript
 Computer >> コンピューター >  >> プログラミング >> JavaScript

JavaScriptで数値をアルファベットにマッピングして全パターンを列挙する方法


課題の内容

ここでは、数値 12145 を例に考えてみます。求められているのは、数値の各桁(または隣接する桁をつなげた2桁)を、以下のルールに従って英語のアルファベットへ対応付ける関数です。

  • アルファベットは1始まりのインデックスで対応付ける
  • 1 →「a」、2 →「b」、3 →「c」…というように、26 →「z」まで割り当てる

一つの数値に複数のマッピングが存在する

実は、同じ数値でも桁の区切り方によって複数の変換結果が生まれます。先ほどの 12145 を例に見てみましょう。

12145 → 1, 2, 1, 4, 5 → abade

最初の2桁をまとめて「12」と見なせば、12番目のアルファベットである「l」に対応させることができます。

12145 → 12, 1, 4, 5 → lade

さらに「14」もまとめると、次のようになります。

12145 → 12, 14, 5 → lne

ただし注意点があります。45 のように26より大きい数値はどのアルファベットにも対応しないため、「1, 2, 1, 45」のような区切り方は無効です。

そこで、今回作成する関数は、こうした制約を満たす有効なマッピングのすべての組み合わせを配列として返す必要があります。

実装コード

再帰処理を用いて、「1桁ずつ進むパターン」と「2桁まとめて進むパターン」を同時に探索するのがポイントです。

const num = 12145;

const mapToAlphabets = num => {
    const numStr = '' + num;
    let res = [];

    const shoveElements = (left, right) => {
        // 残りの数字がなくなったら、結果を確定させる
        if (!left.length) {
            res.push(right.map(el => {
                return (+el + 9).toString(36);
            }).join(''));
            return;
        };
        // 先頭の1桁が0以外なら、その1桁でマッピングを試す
        if(+left[0] > 0){
            shoveElements(left.slice(1), right.concat(left[0]));
        };
        // 先頭の2桁が26以下なら、その2桁でマッピングを試す
        if(left.length >= 2 && +(left.slice(0, 2)) <= 26){
            shoveElements(left.slice(2), right.concat(left.slice(0, 2)));
        };
    };

    shoveElements(numStr, []);
    return res;
}
console.log(mapToAlphabets(num));

コードのポイント解説

  • (+el + 9).toString(36):36進数表記では、0〜9 の次に a〜z が続くため「10」が「a」、「11」が「b」に対応します。各数値に9を加算することで、1→a、2→b…という変換をシンプルに実現しています。
  • shoveElements 関数:未処理の数字列(left)と、これまでに確定した部分(right)を受け取る再帰関数です。1桁で進むケースと2桁(26以下)で進むケースの両方を再帰的に辿ることで、すべての有効な組み合わせを漏れなく探索できます。

実行結果

コンソールへの出力は以下の通りです。

[ 'abade', 'abne', 'aude', 'lade', 'lne' ]

5通りの有効なマッピングパターンがすべて取得できていることが確認できます。この手法は、いわゆる「Decode Ways(デコードの方法)」と呼ばれる典型的なバックトラッキング問題にも応用できるため、再帰による全探索の練習としても最適です。

  1. JavaScriptのMap(マップ)オブジェクトとは?基本的な使い方をサンプルコード付きで解説

    MapオブジェクトとはMap(マップ)オブジェクトは、ES6(ECMAScript 2015)で導入された組み込みオブジェクトの一つで、「キー」と「値」のペアで構成される要素を管理するコレクションです。通常のオブジェクトとよく似ていますが、Mapの大きな特徴は、キーにオブジェクトやプリミティブ値など、あらゆる型の値を使用できる点にあります。さらに、要素は挿入した順序で保持されるため、for...ofループなどを利用して、追加した順番どおりに反復処理を行うことも可能です。Mapオブジェクトの主なメソッドとプロパティメソッド / プロパティ説明new Map(iterable)配列などのイテラブル

  2. JavaScriptのエスケープ文字とは?特殊文字のエスケープ方法と一覧を解説

    エスケープ文字とは?エスケープ文字とは、プログラム上で本来意図した意味とは別の特別な意味に解釈されてしまう文字のことです。たとえば、ダブルクォートやシングルクォート、改行コードなどが該当します。こうした文字を「そのままの文字」として扱い、画面に出力したい場合には、直前にバックスラッシュ「\」を付けて記述します。この操作を「エスケープ処理」と呼びます。JavaScriptの主なエスケープ文字一覧コード意味・出力結果\bバックスペース\fフォームフィード\n改行(ニューライン)\rキャリッジリターン\t水平タブ\v垂直タブ\シングルクォート()\ダブルクォート()\\バックスラッシュ(\)バックス