4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

`slice(1, -1)`って何してるの - 回文の真偽判定を再帰的に解く

Posted at

isPalindrome(): A recursive approach
What Does slice(1, -1) Do?, (slice(1, -1)って何してるの)
を元ネタにした日本語によるまとめ。

要約

メジャーなプログラミング題材である、「回文の真偽判定」。
Project Euler in JavaScript
js 回文の真偽判定

教科書どおり

function isPalindrome (str) {
  let len = 0;

  // remove non-alphanumeric characters and
  // change the string to lowercase
  // and get the length of the string
  str = str.replace(/[^a-z0-9]/i, '').toLowerCase();
  len = str.length;

  // calculate the string midpoint position and
  // loop through the characters up to the midpoint
  // comparing characters in corresponding positions
  // from the start of the string and the end of the string
  for (let i = 0, mid = len >> 1; i < mid; i++) {
    if (str[i] !== str[len - i - 1]) return false;
  }  

  // if execution reaches here, the character comparisons matched
  // and the string (if not empty) must be a palindrome
  return len > 0;
}

sliceでこう書ける


function isPalindrome (str) {
  // remove non-alphanumeric characters and
  // change the string to lowercase
  str = str.replace(/[^a-z0-9]/i, '').toLowerCase();

  // and get the length of the string
  const len = str.length;

  if (len <= 1) return true;
  if (str[0] !== str[len - 1]) return false;

  // proper tail call optimized recursion
  return isPalindrome(str.slice(1, -1));
}

内部再帰関数 _isPalindrome()


const isPalindrome = (() => {
  /**
   * This function is returned immediately
   * from the invocation of the outer arrow function
   * and is assigned to the `isPalindrome` identifier.
   */
  return function isPalindrome (str) {
    // remove non-alphanumeric characters and
    // change the string to lowercase
    str = str.replace(/[^a-z0-9]/i, '').toLowerCase();

    // call the recursive _isPalindrome function with string (if not empty)
    // and return the result
    return (str.length > 0) && _isPalindrome(str);
  };

  /**
   * Internal recursive `_isPalindrome()` function
   * optimized for recursion with proper tail call.
   *
   * A single reference to this function is created and stored
   * after the immediate invocation of the outer arrow function,
   * not accessible outside the scope of the outer arrow function,
   * but accessible to `isPalindrome()` via closure.
   */
  function _isPalindrome (str) {
    const len = str.length;

    if (len <= 1) return true;
    if (str[0] !== str[len - 1]) return false;

    // proper tail call
    return _isPalindrome(str.slice(1, -1));
  }
})();

更に最適化

const isPalindrome = (() => {
  return function isPalindrome (str) {
    str = str.replace(/[^a-z0-9]/i, '').toLowerCase();
    // wrap the recursive _isPalindrome function with _trampoline()
    return (str.length > 0) && _trampoline(_isPalindrome)(str);
  };

  // trampoline() — higher-order function
  function _trampoline (fn) {
    return function _trampolined (...args) {
      let result = fn(...args);
      while (typeof result === 'function') {
        result = result();
      }
      return result;
    }
  }

  function _isPalindrome (str) {
    const len = str.length;

    if (len <= 1) return true;
    if (str[0] !== str[len - 1]) return false;

    // return a function that calls the recursive function
    return () => _isPalindrome(str.slice(1, -1));
  }
})();

sliceとは

javascript sliceメソッド
javascriptのStringのsubstring slice substr

const str = "deluxe";

console.log(str.slice(2));
// luxeが返る

console.log(str.slice(2, 4));
// luが返る

console.log(str.slice(1, 6));
// eluxeが返る

console.log(str.slice(1, -1));
// eluxが返る
const str = 'マツコ';
console.log(str.slice(1, 2));

console.log(str.slice(1, -1));

//いずれも ツが返る

const str = 'マツコDeluxe';
console.log(str.slice(1, 2));
// ツが返る

console.log(str.slice(1, -1));
// ツコDeluxが返る

つまり What Does slice(1, -1) Do?, (slice(1, -1)って何してるの)

今日は、slice(1, -1)が何をするのかを学んだ。
文字列が回文かどうかを (再帰的に) チェックする方法を調べていたら、 str.slice(1, -1) を使う解決策に出くわしました。

配列を変異させずに処理したい場合は slice() が良い選択肢となります。
負のインデックスを使用して、シーケンスの終わりからを示すことができます。

という話でありました。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?