Help us understand the problem. What is going on with this article?

配列を再帰的に処理する関数いろいろ

More than 5 years have passed since last update.

関数というか静的メソッドですけど。

PHP5以降であれば多分動くと思います。
5.3未満のためにクロージャは消しました。
また、ソート関数に関してはソートフラグを設定するとNoticeが発生するリスクがあるのでオプション無しという方針で書きました。
デバッグ不足だと思うのでバグを見つけられた方は是非報告を。

interface RecursiveArrayInterface {

    /* 各ソート関数再帰対応版。オプション無し。 */
    public static function sort(array &$arr);
    public static function rsort(array &$arr);
    public static function asort(array &$arr);
    public static function arsort(array &$arr);
    public static function ksort(array &$arr);
    public static function krsort(array &$arr);
    public static function natsort(array &$arr);
    public static function natcasesort(array &$arr);

    /* shuffle()再帰対応版。$preserve_keysをTrueにするとキーが保持される。 */
    public static function shuffle(array &$arr, $preserve_keys = false);

    /* array_change_key_case()再帰対応版。 */
    public static function changeKeyCase(array $arr, $case = CASE_LOWER);

    /* array_combine()再帰対応版。元の関数と違い、$keyと$valuesで構造が違う場合もエラーを発生しない。 */
    public static function combine(array $keys, array $values);

    /* array_values()再帰対応版。 */
    public static function values(array $arr);

    /* array_reverse()再帰対応版。 「数値キーの場合のみ...」とかややこしいので
       $preserve_keysの効力を絶対的にした。 */
    public static function reverse(array $arr, $preserve_keys = false);

    /* array_filter()再帰対応版。元の関数と違い、デフォルトではキーは振り直される。
       $preserve_keysをTrueにするとキーが保持される。*/
    public static function filter(array $arr, $callback = '', $preserve_keys = false);

    /* array_map()再帰対応版。配列は1つしか受け付けない。 */
    public static function map($callback, array $arr);

    /* 配列の葉要素のみを取り出して返す関数。$preserve_keysをTrueにするとキーが保持され、
       キーが重複した場合後から出現したものが優先される。 */
    public static function flatten(array $arr, $preserve_keys = false);

    /* array_sum()再帰対応版。 */
    public static function sum(array $arr);

    /* array_product()再帰対応版。 */
    public static function product(array $arr);

    /* array_unique()再帰対応版。一般的なarray_unique_recursive()と異なり、子要素の中の
       キーや順番が異なるが値が重複している配列は等しいとみなされる。 $preserve_keysを
       Trueにするとキーが保持されるが、重複しているものがあった場合どのキーが使われるか
       は未定義とする。*/
    public static function unique(array $arr, $preserve_keys = false);

}

class RecursiveArray implements RecursiveArrayInterface {

    private static $tmp;

    public static function sort(array &$arr) {
        foreach ($arr as &$item) {
            if (is_array($item)) {
                self::sort($item);
            }
        }
        return sort($arr);
    }

    public static function rsort(array &$arr) {
        foreach ($arr as &$item) {
            if (is_array($item)) {
                self::rsort($item);
            }
        }
        return rsort($arr);
    }

    public static function asort(array &$arr) {
        foreach ($arr as &$item) {
            if (is_array($item)) {
                self::asort($item);
            }
        }
        return asort($arr);
    }

    public static function arsort(array &$arr) {
        foreach ($arr as &$item) {
            if (is_array($item)) {
                self::arsort($item);
            }
        }
        return arsort($arr);
    }

    public static function ksort(array &$arr) {
        foreach ($arr as &$item) {
            if (is_array($item)) {
                self::ksort($item);
            }
        }
        return ksort($arr);
    }

    public static function krsort(array &$arr) {
        foreach ($arr as &$item) {
            if (is_array($item)) {
                self::krsort($item);
            }
        }
        return krsort($arr);
    }

    public static function natsort(array &$arr) {
        foreach ($arr as &$item) {
            if (is_array($item)) {
                self::natsort($item);
            }
        }
        return natsort($arr);
    }

    public static function natcasesort(array &$arr) {
        foreach ($arr as &$item) {
            if (is_array($item)) {
                self::natcasesort($item);
            }
        }
        return natcasesort($arr);
    }

    public static function shuffle(array &$arr, $preserve_keys = false) {
        foreach ($arr as &$item) {
            if (is_array($item)) {
                self::shuffle($item, $preserve_keys);
            }
        }
        if ($preserve_keys) {
            $keys = array_keys($arr);
            $ret = shuffle($keys);
            $new = array();
            foreach ($keys as $key) {
                $new[$key] = $arr[$key];
            }
            $arr = $new;
            return $ret;
        } else {
            return shuffle($arr);
        }
    }

    public static function changeKeyCase(array $arr, $case = CASE_LOWER) {
        $ret = array();
        foreach ($arr as $key => $item) {
            $key = $case === CASE_UPPER ? strtoupper($key) : strtolower($key);
            if (is_array($item)) {
                $item = self::changeKeyCase($item, $case);
            }
            $ret[$key] = $item;
        }
        return $ret;
    }

    public static function combine(array $keys, array $values) {
        $keys = array_values($keys);
        $values = array_values($values);
        $ret = array();
        foreach ($keys as $i => $key) {
            if (!isset($values[$i])) {
                break;
            }
            $ret[$key] = $values[$i];
        }
        return $ret;
    }

    public static function values(array $arr) {
        $ret = array();
        foreach ($arr as $item) {
            if (is_array($item)) {
                $item = self::values($item);
            }
            $ret[] = $item;
        }
        return $ret;
    }

    public static function reverse(array $arr, $preserve_keys = false) {
        foreach ($arr as &$item) {
            if (is_array($item)) {
                $item = self::reverse($item, true);
            }
        }
        return $preserve_keys ? $arr : array_values($preserve_keys);
    }

    public static function filter(array $arr, $callback = '', $preserve_keys = false) {
        foreach ($arr as &$item) {
            if (is_array($item)) {
                $item = self::filter($item, $callback, $preserve_keys);
            }
        }
        $arr = array_filter($arr, $callback);
        return $preserve_keys ? $arr : array_values($preserve_keys);
    }

    public static function map($callback, array $arr) {
        self::$tmp = $callback;
        array_walk_recursive($arr, array(__CLASS__, '_map'));
        return $arr;
    }

    public static function flatten(array $arr, $preserve_keys = false) {
        self::$tmp = array();
        array_walk_recursive($arr, array(__CLASS__, '_flatten'), $preserve_keys);
        return self::$tmp;
    }

    public static function sum(array $arr) {
        self::$tmp = 0;
        array_walk_recursive($arr, array(__CLASS__, '_sum'));
        return self::$tmp;
    }

    public static function product(array $arr) {
        self::$tmp = 1;
        array_walk_recursive($arr, array(__CLASS__, '_product'));
        return self::$tmp;
    }

    public static function unique(array $arr, $preserve_keys = false) {
        $base = $arr;
        self::sort($base);
        self::asort($arr);
        list($base, $arr) = self::_unique($base, $arr);
        return $preserve_keys ? $arr : $base;
    }

    private static function _map(&$v) {
        $tmp = self::$tmp;
        $v = $tmp($v);
    }

    private static function _flatten($v, $k, $preserve_keys) {
        if ($preserve_keys) {
            self::$tmp[$k] = $v;
        } else {
            self::$tmp[] = $v;
        }
    }

    private static function _sum($v) {
        self::$tmp += $v;
    }

    private static function _product($v) {
        self::$tmp *= $v;
    }

    private static function _unique(array $base, array $arr) {
        $ret = array(array(), array());
        $keys = array_keys($arr);
        $values = array_values($arr);
        foreach ($base as $i => $item) {
            if (is_array($item)) {
                list($item, $values[$i]) = self::_unique($item, $values[$i]);
            }
            $serial = serialize($item);
            if (!isset($check[$serial])) {
                $check[$serial] = 1;
                $ret[0][] = $item;
                $ret[1][$keys[$i]] = $values[$i];
            }
        }
        return $ret;
    }

}
mpyw
古い記事はそのまま参考にしないようにご注意ください
synapse
Synapseは、オンラインサロンサービスにおけるパイオニアとして、かつて存在していたスタートアップです。
https://synapseam.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away