2
2

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.

多次元連想配列に対してキーを基準にunsetする関数が欲しい

Last updated at Posted at 2017-02-06

あるいは多次元連想配列に対してキーを基準に対象配列の構造を維持したまま共通項の末端キーを削除した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は、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ってのもあるらしい。書かれたコードにお目当てのものがあるかもしれないが、コードを一瞥して仕様を理解する能力はない。いくつか試して似ているがちょっと違うものだったので、一旦全部は調査せずに捨て置く。コメント頼み。

例外の使い分けは相変わらずむつかしい。

2
2
3

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
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?