15
14

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 5 years have passed since last update.

任意の文字集合から成るM桁のN進数をジェネレータで生成する

Last updated at Posted at 2015-09-16

はじめに

ここの解答5にて、3進数8桁を生成する解法を使いました。しかし例えばこれがもし62進数10桁のような膨大なスケールになったと仮定すると、以下のような問題が発生します。

  • この解法を使うと整数がオーバーフローする。かといってこれのためにわざわざGMP数やBCMath関数を使うかというと悩みどころ。
  • 再帰させて配列にする方法だと配列生成処理が終わらないあるいはメモリ制限をオーバーする。時間がかかるにしても逐次処理させていきたい。

そこで…PHP5.5で導入されたジェネレータの出番なんです。

実装

※ ジェネレータ内でreturn出来るようになったのはPHP7以降のようであり、それより古い環境に対応させるためにreturnを使わずに済む条件分岐に書き換えました。

ジェネレータ定義

  • 長さが2以上のとき、現コールスタックから見た最大桁を生成し、そのそれぞれについて、残りの全ての桁が結合されたものを再帰呼び出しによって生成します。これらを結合して返します。
  • 長さが2未満1以上のとき、1桁だけを生成して返します。
  • 長さが1未満のとき、生成を即座に終了します。実際に再帰でこの呼び出しが行われることはありません。
function generate(array $chars, $length) {
    if ($length >= 2) {
        foreach ($chars as $char) {
            foreach (generate($chars, $length - 1) as $string) {
                yield $char . $string;
            }
        }
    } elseif ($length >= 1) {
        foreach ($chars as $char) {
            yield $char;
        }
    }
}
(参考) ジェネレータの代わりに配列を生成する場合のコード
function collect(array $chars, $length) {
    if ($length >= 2) {
        $strings = [];
        foreach ($chars as $char) {
            foreach (collect($chars, $length - 1) as $string) {
                $strings[] = $char . $string;
            }
        }
        return $strings;
    } elseif ($length >= 1) {
        return $chars;
    } else {
        return [];
    }
}

使用例

// 半角英数字とアンダースコア
$chars = array_merge(
    range(0, 9),
    range('a', 'z'),
    range('A', 'Z'),
    ['_']
);

// 3桁で出力
foreach (generate($chars, 3) as $string) {
    echo $string . PHP_EOL;
}

/*
000
001
002
003
004
...
__W
__X
__Y
__Z
___
*/
15
14
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
15
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?