指定したシーケンスを生成するのは楽しいチャレンジでした。
以下のこのコードは、あなたが望むことをするはずです(私は思います)。または、少なくとも、ニーズに合わせて変更できるはずです。sequences()
関数がテスト関数$functions[$func]
が返す最初のシーケンスのみを返すようにしたいのtrue
か、それともこれまでのすべてのシーケンスを返すようにしたいのか、正確にはわかりませんでした。この例では、最初の「一致」のみが返されます (またはnull
、一致が見つからなかった場合)。
このコードは、ジェネレーター関数 (および PHP 5.4 以降で使用可能な短い配列構文) を使用するため、PHP 5.5 以降が必要です。これを PHP 5.5.12 でテストしたところ、意図したとおりに動作するようです。必要に応じて、古いバージョンの PHP で動作するようにコードを変更することができます (ジェネレーター/yield の使用は避けてください)。実はPHPジェネレーター関数を書いたのはこれが初めてです。
sequenceGenerator()
を使用して反復できる再帰的なジェネレーター関数ですforeach
。
また、echoSequences()
echo を使用して、生成されたすべてのシーケンスを順番に出力するだけのシーケンス生成をテストするための関数も作成しました。
function sequenceGenerator(array $items, $long = null, $level = 1, $path = null) {
$itemCount = count($items);
if (empty($long)) $long = $itemCount;
if ($path == null) $path = [];
if ($itemCount > 1) {
foreach ($items as $item) {
$subPath = $path;
$subPath[] = $item;
if ($level == $long) {
yield $subPath;
continue;
}
if (count($subPath) + count($items) > $long) {
$items = array_values(array_diff($items, [$item]));
$iteration = sequenceGenerator($items, $long, $level + 1, $subPath);
foreach ($iteration as $value) yield $value;
}
}
} elseif ($itemCount == 1) {
$path[] = $items[0];
yield $path;
}
}
// Function for testing sequence generation
function echoSequences($smallest, $biggest, $long) {
$items = range($smallest, $biggest);
foreach (sequenceGenerator($items, $long) as $sequence) {
echo implode(',', $sequence)."<br>\n";
}
}
function sequences($smallest, $biggest, $long, $func) {
global $functions;
$items = range($smallest, $biggest);
foreach (sequenceGenerator($items, $long) as $sequence) {
if (call_user_func($functions[$func], $sequence)) {
return $sequence;
}
}
return null; // Return null when $func didn't return true for any sequence
}
//echoSequences(5, 10, 4); // Test sequence generation
$functions = array(
// This test function returns true only for the sequence [5,6,8,10]
'testfunc' => function($sequence) { return ($sequence == [5,6,8,10]); }
);
$sequence = sequences(5, 10, 4, 'testfunc'); // Find the first sequence that 'testfunc' will return true for (or null)
if (!empty($sequence)) {
echo 'Found match: '.implode(',', $sequence);
} else {
echo 'Match not found';
}