私の提案は、ループに入る前に配列から最初の値を抽出して削除し、一時的な配列($carry
)を使用して、新しい値がそれぞれキャリー配列のキーと一致するかどうかを追跡することです。もしそうなら、それをインクリメントします。そうでない場合は、完了したシーケンスカウントを結果配列にプッシュし、キャリーを新しい値で上書きして、カウンターを1に設定します。ループが終了したら、残りのキャリーを結果セットにプッシュします。私のスニペットは、入力配列が空かどうかをチェックしません。必要に応じて、その条件をプロジェクトに追加します。
コード:(デモ)
$array = [1,1,1,2,2,3,3,1,1,2,2,3];
$result = [];
$carry = [array_shift($array) => 1];
foreach ($array as $value) {
if (isset($carry[$value])) {
++$carry[$value];
} else {
$result[] = $carry;
$carry = [$value => 1];
}
}
$result[] = $carry;
print_r($result);
出力:(ページの肥大化を減らすために圧縮されます)
[
[1 => 3],
[2 => 2],
[3 => 2],
[1 => 2],
[2 => 2],
[3 => 1],
]
zerkmsスタイルの参照による変更スタイルの手法を実装する場合は、次のスニペットで上記のスニペットと同じ結果が得られます。
事実上、新しく検出されたすべての値を、関連する単一要素の配列として、インデックス付きの結果配列にプッシュします。プッシュされたサブ配列は変数($carry
)として宣言され、参照によって結果配列に割り当てられる(= &
)ため、の増分は$carry
結果配列内の深くネストされた値に適用されます。出力配列には、複数回発生する特定の値を確実に格納できるように、構造に追加の深さが必要です。
コード:(デモ)
$result = [];
$carry = [];
foreach ($array as $value) {
if ($carry && key($carry) === $value) {
++$carry[$value];
} else {
unset($carry);
$carry = [$value => 1];
$result[] = &$carry;
}
}
unset($carry);
print_r($result);
ループの後で参照変数を設定解除する$carry
必要はないかもしれませんが、変数のスコープ内でその変数が再利用される可能性がある場合は、参照を。で切り離すことが重要になりますunset()
。
そして、楽しみのために、サンプルデータで機能する恐ろしい正規表現を取り入れたアプローチを次に示します。デモ