phpで[0,...10]までの配列を2個、3個、2個……となるようにarray_chunkしようとしたら大変なことになった


たまにこういうことってあると思うんですね。
画面上の列の構成が1行目は2個、2行目は3個……みたいな。
CSSで対応できないこともないんですが、PHP側でそういう対応が必要になってしまった場合に。

2個ずつ、3個ずつ、ということであればarray_chunk一発で簡単だったんですが……

まずはシンプルにッ!

simple_chunk.php
$azunyan = range(0, 10);

$peropero = [];
while (count($azunyan)) {
    $peropero[] = array_splice($azunyan, 0, count($peropero) % 2 ? 3 : 2);
}

// [[0,1], [2,3,4], [5,6], [7,8,9], [10]]
var_dump($peropero);

シンプルに実装してみました。
2個、3個となるように、array_spliceに渡す値を制御しています。
生のPHPでやるのであれば、これが普通だと思います。

燃え上がる反骨心


何をトチ狂ったのか、\$azunyanを用意したくないし、
\$peroperoの空配列の変数も事前に用意したくないし、
[]で繋ぎ合わせたくないという反骨心が生まれてしまいましたッ!!

yieldしてみようッ!

yield_chunk.php
$peropero = iterator_to_array((function ($values) {
    while (count($values)) {
        yield array_splice($values, 0, 2);
        if (count($values)) yield array_splice($values, 0, 3);
    }
})(range(0, 10)));

var_dump(var_dump);

$peroperoに随時追加しないようにするのであれば、2個、3個……というchunkの結果を返す関数を作ればいいのでは?
けど関数だと結局、内部で変数を定義して処理しないといけなさそうだな……ならiteratorにして、結果を配列として受け取るようにしてしまえばいいのでは?という発想から誕生したコードになります。

これでも分割はできるんですが、whileの中で条件分岐ができなくなってしまったため、
yieldが2段階構成+if文が必要になるし、行も増えてしまうというイマイチな作りに。

行は減らしたいし、ifも書きたくないッ!

chunk_splice_merge.php
$peropero = call_user_func_array("array_merge", array_map(function($target) {
    return array_filter([array_splice($target, 0, 2), $target]);
}, array_chunk(range(0, 10), 5)));

var_dump($peropero);

行は減らしたいし、ifも書きたくないという贅沢な条件を満たしてみました。

2個、3個……という流れにするんであれば……
まず5個ずつに分割して、それを更に2個、3個に分割して、最終的にflatすれば良くないかという結論に。

flatする関数が生のphpでは存在しないという事実に心が折れかけましたが、
javascriptでいうスプレッド演算子的なのがあれば、array_mergeで2次元を1次元に落とせるのではと。
call_user_func_arrayの存在を思い出して、array_mergeで呼んであげています。

yieldの時に問題になったif文はarray_filterを実行することで取り除くようにしています。

結論ッ!

こんな見にくい処理をprに出したら怒られてしまうので、最初からシンプルに書いた処理にしておきましょう。