あるいは多次元連想配列に対してキーを基準に対象配列の構造を維持したまま共通項の末端キーを削除したdiffを取る関数。
絶対どこかにあるだろうけど言語化の不自由と情報の海に埋もれてうまく検索できないシリーズ
コード
<?php
$haystack = [
'A' => [
'い' => 'i',
'ろ' => 'ro',
'は' => 'ha',
],
'B' => [
'one' => '1',
'two' => '2',
'three' => '3',
],
'C' => [
'い' => 'a',
'two' => 'b',
'う' => 'c',
'A' => ['...'], // もっと深くても良い
],
];
$needles = [
'A' => [
'い' => '',
'は' => [],
],
'B' => [
'two' => null,
],
'C' => false,
];
$unset = function ($needles, &$haystack) use (&$unset) {
foreach ($needles as $key => $value) {
// $needlesは完璧に$haystackの構造を把握しているものとしてみる
if (!isset($haystack[$key])) {
// TODO 例外がいいのか、どの例外がいいのか
throw new OutOFBoundsException('Undefined index:' . $key . "\n" . 'haystack:' . print_r($haystack, true));
}
// 空配列にも対応しようとすると、ただのemptyでいい気がするけど、意図を、ね。trueとかも穴になるし。
if (!is_array($value) || empty($value)) {
unset($haystack[$key]);
continue;
}
if (is_array($value)) {
$unset($value, $haystack[$key]);
continue;
}
throw new LogicException('value => ' . $value . "\n" . 'key => ' . $key);
}
};
$unset($needles, $haystack);
print_r($haystack);
Array
(
[A] => Array
(
[ろ] => ro
)
[B] => Array
(
[one] => 1
[three] => 3
)
)
要件
- 多次元連想配列(以降haystack)の任意の階層にある任意のキーを任意個削除(
unset
)したい。 - 削除対象を指定する方法は、階層とキーが必要なので、
array
以外の値を考慮しない同構造の連想配列で指定することとする。(以降needles)- つまり、needlesの値が配列ならその配列を再帰調査、配列以外ならキーをまるごと
unset
。
- つまり、needlesの値が配列ならその配列を再帰調査、配列以外ならキーをまるごと
- needlesは、haystackの構造を完全に把握しているとしてみる。
- needlesには、 haystackに無いキーが現れてはならない。
- 非配列のvalueを比較考慮しないのはneedlesを楽に書きたかったから。
- 非破壊が望ましいが、強くこだわらない。(できなかった…)
- haystackにスキーマ、構造、ルールは存在しない。(2次元目は一律hogeとhugaと~みたいな決まりは無い)
- haystackの値は同配列内でかぶる可能性があるし、任意の型である。(
array_flip
の排斥)
これらを上手くキーワード化できないので検索が厳しい。
考えたこと
foreach
とかで考えると潜るごとにキーを覚えていかないといけないから2次元ぐらいならともかくn次元はしんどそう
添字配列は値の振り直しとか考えちゃうからひとまず連想配列でいいや
needlesは値が配列じゃなかったら([キー => 使わないダミー値]とせずとも)値をキーとしてunset
ってすれば記述量が減りそうだけど、haystackと配列の見た目がミラーっぽくなくなる?
ある配列の中身が全部unset
されて空配列になった場合はその配列も消すべき?でもhaystackを把握している前提なら全部消さずに上位のキーだけ指定すればいいし…
PHPのneedleとhaystackの並び順がばらばらな所、好きじゃないよ
array_diff_key
単体では無理そうだけどunset
でなくarray_diff_key
で新しい結果配列作ったりとかは出来そうなんだけど、
結果配列連れ回す引数増えそうとかで、
ってコード書いた後に見てみたらユーザーノートにいろいろあるし、array_diff_assoc
ってのもあるらしい。書かれたコードにお目当てのものがあるかもしれないが、コードを一瞥して仕様を理解する能力はない。いくつか試して似ているがちょっと違うものだったので、一旦全部は調査せずに捨て置く。コメント頼み。
例外の使い分けは相変わらずむつかしい。