原文: Three Ways to Reverse a String in JavaScript (Sonya Moisset)

翻訳・翻案: Yoko Matsuda

この記事の内容は freeCodeCamp の課題 Basic Algorithm Scripting "Reverse a String" を元にしています。

文字列の反転は、技術面接でよく問われる JavaScript の問題の一つです。異なる方法をいくつか回答するよう求められたり、組み込みメソッドを使用しない方法や、再帰関数を使用する方法を問われることもあるかもしれません。

JavaScript には組み込みの reverse 関数 (文字列を反転させる関数) がありませんが、その他に多数の方法があります。

以下で、私がもっとも興味深いと思う 3 つの方法を解説します。

課題

与えられた文字列を反転させてください。
文字列を反転させる前段階として、文字列を配列に変換する必要があるかもしれません。
結果は文字列でなければなりません。
function reverseString(str) {
    return str;
}
reverseString("hello");

テストケース

  • reverseString(“hello”) の結果は “olleh” となること
  • reverseString(“Howdy”) の結果は “ydwoH”となること
  • reverseString(“Greetings from Earth”) の結果は “htraE morf sgniteerG” となること

1. 組み込み関数を使用して文字列を反転させる

この解法では、次の 3 種類のメソッドを使用します: String.prototype.split(), Array.prototype.reverse(), Array.prototype.join()

  • split() メソッドは文字列を分割し、String オブジェクトを文字列の配列に変換します。
  • reverse() メソッドは配列を反転させます。配列の最初の要素が最後の要素になり、最後の要素が最初の要素になります。
  • join() メソッドは配列内のすべての要素を結合し、文字列に変換します。
function reverseString(str) {
    // Step 1. split() メソッドを使用して配列を作成する
    var splitString = str.split(""); // var splitString = "hello".split("");
    // ["h", "e", "l", "l", "o"]
 
    // Step 2. reverse() メソッドを使用して配列を反転させる
    var reverseArray = splitString.reverse(); // var reverseArray = ["h", "e", "l", "l", "o"].reverse();
    // ["o", "l", "l", "e", "h"]
 
    // Step 3. join() メソッドを使用して配列内のすべての要素を結合して文字列にする
    var joinArray = reverseArray.join(""); // var joinArray = ["o", "l", "l", "e", "h"].join("");
    // "olleh"
    
    //Step 4. 反転した文字列を返す
    return joinArray; // "olleh"
}
 
reverseString("hello");

メソッドチェーンとしてつなげる場合:

function reverseString(str) {
    return str.split("").reverse().join("");
}
reverseString("hello");

2. デクリメントと for ループを使用して文字列を反転させる

function reverseString(str) {
    // Step 1. 新しい文字列を保存するための空の文字列を作成する
    var newString = "";
 
    // Step 2. for ループを作成する
    /* ループの初期値は (str.length - 1) で、文字列の最後の文字 "o" を指す。
       i が 0 以上である限り、ループが続く。
       繰り返し 1 回ごとに i をデクリメントする。(1 減らす) */
    for (var i = str.length - 1; i >= 0; i--) { 
        newString += str[i]; // or newString = newString + str[i];
    }
    /* "hello" の長さは 5 文字なので、以下のようになる。
        各回の値: i = str.length - 1, newString = newString + str[i]
        1 回目:   i = 5 - 1 = 4,      newString = "" + "o" = "o"
        2 回目:   i = 4 - 1 = 3,      newString = "o" + "l" = "ol"
        3 回目:   i = 3 - 1 = 2,      newString = "ol" + "l" = "oll"
        4 回目:   i = 2 - 1 = 1,      newString = "oll" + "e" = "olle"
        5 回目:   i = 1 - 1 = 0,      newString = "olle" + "h" = "olleh"
    for ループ終了 */
 
    // Step 3. 反転させた文字列を返す
    return newString; // "olleh"
}
 
reverseString('hello');

コメントを除いたコード:

function reverseString(str) {
    var newString = "";
    for (var i = str.length - 1; i >= 0; i--) {
        newString += str[i];
    }
    return newString;
}
reverseString('hello');

3. 再帰関数を使用して文字列を反転させる

この解法では、次の 2 種類のメソッドを使用します: tring.prototype.substr(), String.prototype.charAt()

  • substr() メソッドは、文字列内の文字を、指定した開始位置から指定した文字数だけ返します。(訳注: 下記の例では文字数の指定が省略されており、デフォルトの動作として文字列の末尾までが取得されます。)
  • charAt() メソッドは、文字列内の指定した位置の文字を返します。
"hello".substr(1); // "ello"
"hello".charAt(0); // "h"

再帰の深さは文字列の長さと同じになります。この解法は最善ではなく、文字列が著しく長い場合は処理が非常に遅くなり、スタックのサイズが大きな懸念事項となります。

function reverseString(str) {
  if (str === "") // 再帰を終了する終了条件
    return "";
  
  else
    return reverseString(str.substr(1)) + str.charAt(0);
/* 

再帰メソッドの前半
呼び出しが 1 回だけではなく、複数回の呼び出しがネストされることを頭に置いておいてください。

各回の呼び出し:     str === "?"                 reverseString(str.subst(1)) + str.charAt(0)
1 回目の呼び出し – reverseString("Hello")  が  reverseString("ello")       + "h"  を返す
2 回目の呼び出し – reverseString("ello")   が  reverseString("llo")        + "e"  を返す
3 回目の呼び出し – reverseString("llo")    が  reverseString("lo")         + "l"  を返す
4 回目の呼び出し – reverseString("lo")     が  reverseString("o")          + "l"  を返す
5 回目の呼び出し – reverseString("o")      が  reverseString("")           + "o"  を返す

再帰メソッドの後半
if 文の条件を満たすと、一番最後にネストされている呼び出しが返されます。

5 回目の呼び出しが  reverseString("") + "o"      = "o"                          を返す
4 回目の呼び出しが  reverseString("o") + "l"     = "o" + "l"                    を返す
3 回目の呼び出しが  reverseString("lo") + "l"    = "o" + "l" + "l"              を返す
2 回目の呼び出しが  reverserString("llo") + "e"  = "o" + "l" + "l" + "e"        を返す
1 回目の呼び出しが  reverserString("ello") + "h" = "o" + "l" + "l" + "e" + "h"  を返す
*/
}
reverseString("hello");

コメントを除いたコード:

function reverseString(str) {
  if (str === "")
    return "";
  else
    return reverseString(str.substr(1)) + str.charAt(0);
}
reverseString("hello");

条件 (三項) 演算子を使用する場合:

function reverseString(str) {
  return (str === '') ? '' : reverseString(str.substr(1)) + str.charAt(0);
}
reverseString("hello");

JavaScript で文字列を反転させることは、技術面接で質問されやすいシンプルなアルゴリズムです。この問題を短い手順で解くことも、再帰関数やさらに複雑な解法で解くこともできます。

この記事が参考になりましたら幸いです。この記事は、私が “How to Solve FCC Algorithms” シリーズとして freeCodeCamp 上のアルゴリズムに関するチャレンジの解法を解説している記事の一つです。

Three ways to repeat a string in JavaScript (英語)
この記事では、freeCodeCamp の “Repeat a string repeat a string” チャレンジの解法を解説しています。

Two ways to confirm the ending of a String in JavaScript (英語)
この記事では、freeCodeCamp の “Confirm the Ending” チャレンジの解法を解説しています。

Three Ways to Factorialize a Number in JavaScript (英語)
この記事は freeCodeCamp の Basic Algorithm Scripting “Factorialize a Number” に基づいたものです。

Two Ways to Check for Palindromes in JavaScript (英語)
この記事は freeCodeCamp の Basic Algorithm Scripting “Check for Palindromes”に基づいたものです。

Three Ways to Find the Longest Word in a String in JavaScript (英語)
この記事は freeCodeCamp の Basic Algorithm Scripting “Find the Longest Word in a String”に基づいたものです。

Three Ways to Title Case a Sentence in JavaScript (英語)
この記事は freeCodeCamp の Basic Algorithm Scripting “Title Case a Sentence”に基づいたものです。

Medium, Twitter, Github, LinkedIn のフォローもよろしくお願いします。

参考資料