代码之家  ›  专栏  ›  技术社区  ›  tstenner

将数组/对象树的键转换为小写

  •  3
  • tstenner  · 技术社区  · 14 年前

    我目前正在优化一个PHP应用程序,发现有一个函数被调用了大约10-20k次,所以我想我应该从那里开始优化:

    function keysToLower($obj)
    {
            if(!is_object($obj) && !is_array($obj)) return $obj;
            foreach($obj as $key=>$element)
            {
                    $element=keysToLower($element);
                    if(is_object($obj))
                    {
                            $obj->{strtolower($key)}=$element;
                            if(!ctype_lower($key)) unset($obj->{$key});
                    }
                    else if(is_array($obj) && ctype_upper($key))
                    {
                            $obj[strtolower($key)]=$element;
                            unset($obj[$key]);
                    }
            }
            return $obj;
    }
    

    大部分时间都花在递归调用上(在PHP中很慢),但我看不到任何将其转换为循环的方法。 你会怎么做?

    这个版本不考虑关联数组,因为我的数据没有关联数组,但是比原始版本快了近10倍。大部分工作是由Gumbo完成的,主要的加速来自于使用引用和创建新对象,而不是取消设置旧键。

    function &keysToLower(&$obj)
    {
        if(is_object($obj))
        {
            $newobj = (object) array();
            foreach ($obj as $key => &$val)
                $newobj->{strtolower($key)} = keysToLower($val);
            $obj=$newobj;
        }
        else if(is_array($obj))
            foreach($obj as &$value)
                keysToLower($value);
        return $obj;
    }
    
    5 回复  |  直到 12 年前
        1
  •  5
  •   Gumbo    14 年前

    Foreach 正在使用然后遍历的内部副本。试一试:

    function keysToLower($obj)
    {
        $type = (int) is_object($obj) - (int) is_array($obj);
        if ($type === 0) return $obj;
        reset($obj);
        while (($key = key($obj)) !== null)
        {
            $element = keysToLower(current($obj));
            switch ($type)
            {
            case 1:
                if (!is_int($key) && $key !== ($keyLowercase = strtolower($key)))
                {
                    unset($obj->{$key});
                    $key = $keyLowercase;
                }
                $obj->{$key} = $element;
                break;
            case -1:
                if (!is_int($key) && $key !== ($keyLowercase = strtolower($key)))
                {
                    unset($obj[$key]);
                    $key = $keyLowercase;
                }
                $obj[$key] = $element;
                break;
            }
            next($obj);
        }
        return $obj;
    }
    

    或使用引用以避免使用副本:

    function &keysToLower(&$obj)
    {
        $type = (int) is_object($obj) - (int) is_array($obj);
        if ($type === 0) return $obj;
        foreach ($obj as $key => &$val)
        {
            $element = keysToLower($val);
            switch ($type)
            {
            case 1:
                if (!is_int($key) && $key !== ($keyLowercase = strtolower($key)))
                {
                    unset($obj->{$key});
                    $key = $keyLowercase;
                }
                $obj->{$key} = $element;
                break;
            case -1:
                if (!is_int($key) && $key !== ($keyLowercase = strtolower($key)))
                {
                    unset($obj[$key]);
                    $key = $keyLowercase;
                }
                $obj[$key] = $element;
                break;
            }
        }
        return $obj;
    }
    
        2
  •  3
  •   gaborous    12 年前

    您可能还需要查找 array_change_key_case()

        3
  •  2
  •   Oblio    14 年前

    我想你不关心如何投射到数组…

    function keys_to_lower($o) {
        if (is_object($o)) {
            $o = (array)$o;
        }
        if (is_array($o)) {
            return array_map('keys_to_lower', array_change_key_case($o));
        }
        else {
            return $o;
        }
    }
    
        4
  •  2
  •   Kijewski Jim    12 年前

    下面是使用lambda的示例:

    $multiArrayChangeKeyCase = function (&$array) use (&$multiArrayChangeKeyCase) {
        $array = array_change_key_case($array);
    
        foreach ($array as $key => $row)
            if (is_array($row))
                 $multiArrayChangeKeyCase($array[$key]);
    };
    
        5
  •  1
  •   mario    14 年前
    array_combine(array_map("strtolower", array_keys($a)), array_values($a))