Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

вопрос по массивам

15K
11 ноября 2011 года
hel
78 / / 10.11.2007
 
Код:
function getVal($array, $path){}

getVal($array, "Config/DB/Hostname");


Функция должна обратиться к элементу $array["Config"]["DB"]["Hostname"] и возвратить полученное значение. Длина пути должна быть произвольная.

Это реализуемо?
277
11 ноября 2011 года
arrjj
1.7K / / 26.01.2011
Я както с пхп не очень, но так наверно можно:
 
Код:
$path_array=explode("/",$path);
foreach($path_array as $path_element)
$array=$array[$path_element];
return $array;
15K
11 ноября 2011 года
hel
78 / / 10.11.2007
arrjj,
Как то я совсем спросонья повис над задачей.
Спасибо за пример. +1 в карму. :)
13
11 ноября 2011 года
RussianSpy
3.0K / / 04.07.2006
foreach тут не нужен -он медленный
 
Код:
function getVal($array, $path)
{
  $path_array = explode('/',$path);
 
  for($i=0; $i<sizeof($path_array); $i++) $array = $array[$path_array[$i]];
  return $array;
}
4
11 ноября 2011 года
mike
3.7K / / 01.10.2002
Цитата: RussianSpy
foreach тут не нужен -он медленный

Не уверен что explode и создание нового массива быстрее чем foreach.

15K
11 ноября 2011 года
hel
78 / / 10.11.2007
Меня интересует, быстрейший ли это способ. Хочется удобный интерфейс управления объектом глобального сайтового реестра информации сделать. И предполагается что обращений к реестру будет немало. 30-50 на каждую генерацию страницы пользователю.
277
11 ноября 2011 года
arrjj
1.7K / / 26.01.2011
Ну можно вообще сформировать строку а потом её eval'нуть:
 
Код:
$path=str_replace("\"","\\\"",$path);
$path=str_replace("/","\"][\"",$path);
eval("$ret=$array[\"".$path."\"]");
return $ret;

хз на сколько быстро это будет.
13
11 ноября 2011 года
RussianSpy
3.0K / / 04.07.2006
Цитата: mike
Не уверен что explode и создание нового массива быстрее чем foreach.



В первом приведенном примере и foreach и explode и создание массива

274
11 ноября 2011 года
Lone Wolf
1.3K / / 26.11.2006
Цитата: RussianSpy
foreach тут не нужен -он медленный


foreach медленный? если не ошибаюсь он наиболее быстрый из циклов.

13
11 ноября 2011 года
RussianSpy
3.0K / / 04.07.2006
Цитата: Lone Wolf
foreach медленный? если не ошибаюсь он наиболее быстрый из циклов.



Вы ошибаетесь

274
11 ноября 2011 года
Lone Wolf
1.3K / / 26.11.2006
Цитата: RussianSpy
Вы ошибаетесь



может быть

Код:
<?php
$arr = array();
for($i = 0; $i < 300000; $i++) $arr[] = rand();

$time_start1 = microtime(1);
$n = sizeof($arr);
for($i = 0; $i < $n; $i++) {
$a = $arr[$i];
}
$time_end1 = microtime(1);
$time1 = round($time_end1 - $time_start1, 4);

$i = 0;
$time_start2 = microtime(1);
$n = sizeof($arr);
while($i < $n) {
$a = $arr[$i];
$i++;
}
$time_end2 = microtime(1);
$time2 = round($time_end2 - $time_start2, 4);

$time_start3 = microtime(1);
foreach($arr as $key => $val) {
$a = $val;
}
$time_end3 = microtime(1);
$time3 = round($time_end3 - $time_start3, 4);

echo "time1: $time1 s\n";
echo "time2: $time2 s\n";
echo "time3: $time3 s\n";

?>


что в этом коде не так?
271
11 ноября 2011 года
MrXaK
721 / / 31.12.2002
в Kohana есть класс Arr, который позволяет обращаться именно так (только через точку по умолчанию)) главное, что он ещё позволяет обратиться someArr.some2Arr.*
Код:
/**
     * Gets a value from an array using a dot separated path.
     *
     *     // Get the value of $array['foo']['bar']
     *     $value = Arr::path($array, 'foo.bar');
     *
     * Using a wildcard "*" will search intermediate arrays and return an array.
     *
     *     // Get the values of "color" in theme
     *     $colors = Arr::path($array, 'theme.*.color');
     *
     *     // Using an array of keys
     *     $colors = Arr::path($array, array('theme', '*', 'color'));
     *
     * @param   array   array to search
     * @param   mixed   key path string (delimiter separated) or array of keys
     * @param   mixed   default value if the path is not set
     * @param   string  key path delimiter
     * @return  mixed
     */

    public static function path($array, $path, $default = NULL, $delimiter = NULL)
    {
        if ( ! Arr::is_array($array))
        {
            // This is not an array!
            return $default;
        }

        if (is_array($path))
        {
            // The path has already been separated into keys
            $keys = $path;
        }
        else
        {
            if (array_key_exists($path, $array))
            {
                // No need to do extra processing
                return $array[$path];
            }

            if ($delimiter === NULL)
            {
                // Use the default delimiter
                $delimiter = Arr::$delimiter;
            }

            // Remove starting delimiters and spaces
            $path = ltrim($path, "{$delimiter} ");

            // Remove ending delimiters, spaces, and wildcards
            $path = rtrim($path, "{$delimiter} *");

            // Split the keys by delimiter
            $keys = explode($delimiter, $path);
        }

        do
        {
            $key = array_shift($keys);

            if (ctype_digit($key))
            {
                // Make the key an integer
                $key = (int) $key;
            }

            if (isset($array[$key]))
            {
                if ($keys)
                {
                    if (Arr::is_array($array[$key]))
                    {
                        // Dig down into the next part of the path
                        $array = $array[$key];
                    }
                    else
                    {
                        // Unable to dig deeper
                        break;
                    }
                }
                else
                {
                    // Found the path requested
                    return $array[$key];
                }
            }
            elseif ($key === '*')
            {
                // Handle wildcards

                $values = array();
                foreach ($array as $arr)
                {
                    if ($value = Arr::path($arr, implode('.', $keys)))
                    {
                        $values[] = $value;
                    }
                }

                if ($values)
                {
                    // Found the values requested
                    return $values;
                }
                else
                {
                    // Unable to dig deeper
                    break;
                }
            }
            else
            {
                // Unable to dig deeper
                break;
            }
        }
        while ($keys);

        // Unable to find the value requested
        return $default;
    }


а по поводу скорости foreach и вообще скорости всего: http://www.phpbench.com/
ну и на stackoverflow можно ещё поискать

кстати, похоже, что это быстрейшее решение (особенно если исключить всякие проверки), так как в отличие от решений выше результат функции explode не проходится никакими foreach'ами, а получается через array_shift().. это явно быстрее, правда приводит к уничтожению массива.. но по сути он в конце и не нужен
и главное по ссылке этой функции исходный массив не передавать, а то она его тоже затрёт (строка 75)
15K
12 ноября 2011 года
hel
78 / / 10.11.2007
Дело в том, что мне нужно и устанавливать значение по выбранной ветке реестра. И добавлять новые ветки реестра к существующему. Вариант без шифта массива предпочтительней.
А как дела обстоят с eval? Быстрый ли он?
66K
12 ноября 2011 года
onerror
45 / / 05.07.2011
Цитата: RussianSpy
foreach тут не нужен -он медленный
 
Код:
function getVal($array, $path)



Вы тоже ошибаетесь. Принципиально. Что вернёт ваша функция, если её вызвать со следующими параметрами:

 
Код:
$array = array('a' => array('a'));
echo getVal($array, 'a/b/c/');

?
66K
12 ноября 2011 года
onerror
45 / / 05.07.2011
Цитата: hel
Вариант без шифта массива предпочтительней.



Не бойтесь, shift не применяется к массиву, в котором ищутся элементы. Он применяется к сгенерированному (временному) массиву ключей, которые используются для поиска.

15K
12 ноября 2011 года
hel
78 / / 10.11.2007
Цитата: onerror
Не бойтесь, shift не применяется к массиву, в котором ищутся элементы. Он применяется к сгенерированному (временному) массиву ключей, которые используются для поиска.


При использовании shift я не смогу установить значение в исходный массив. В этом и вся загвоздка.

74K
12 ноября 2011 года
OlegSobachnik
14 / / 11.11.2011
А для чего такие сложности? Почему не использовать просто одноуровневый массив для конфига? Обращаться будет просто и не нужно лишний раз дёргать функции для работы со строками и использовать циклы...
66K
12 ноября 2011 года
onerror
45 / / 05.07.2011
Ну, не используйте shift. Вам показали варианты, как можно получить все элементы и без него (с foreach или for). На этом этапе (пока вы даже получить значение не можете) вы не заметите отличий в скорости (если они есть).
15K
12 ноября 2011 года
hel
78 / / 10.11.2007
OlegSobachnik,
По вашему в реестре я собираюсь хранить только конфиг? Было бы смешно только ради этого так изголяться.
В реестр будут вноситься абсолютно все полученные и сгенерированные данные. Я лишь хочу сделать хранилище данных иерархичным, самый быстрый и удобный способ - это многомерный массив.

onerror,
Реализация с foreach,for мне понятна. Она хороша. Меня интересует, будет ли с eval работать быстрее.
66K
12 ноября 2011 года
onerror
45 / / 05.07.2011
Никто вам этого не скажет. А скажут - не поверите! :-) Надо проверять самому на практике. Думаю, что eval принципиально медленнее чего угодно другого (но опять же вряд ли это будет заметно). Для установки значения можно, кстати, использовать ровно те же предложенные функции, только с & (передачей по ссылке):

 
Код:
function setVal(&$array, $path, $new_value)
{
  $path_array = explode('/',$path);
  for($i=0; $i<sizeof($path_array); $i++)
      $array =& $array[$path_array[$i]];
  $array = $new_value;
}
$rr = array('a' => array('b' => array('c' => 'd')));
setVal($rr, 'a/b/c', 'e');
print_r($rr);
271
12 ноября 2011 года
MrXaK
721 / / 31.12.2002
если вы хотите иерархическое хранилище данных - юзайте MongoDB))) не работал с ней в пхп, но в питоне, например, я могу положить в базу dict (аналог ассоциативного массива) любой сложности и спокойно и искать и добавлять что угодно))

Цитата:
При использовании shift я не смогу установить значение в исходный массив. В этом и вся загвоздка.


shift применяется к массиву, созданному из строки вашего поиска, то есть к 'aaaa/bbb/vard', как справедливо заметил onerror.. вам никто не мешает в кохановской функции в else написать не break, а установку значения у этого ключа (строка 115)))

и вообще в той же kohana есть и установка значений по ключу:

Код:
/**
    * Set a value on an array by path.
    *
    * @see Arr::path()
    * @param array   $array     Array to update
    * @param string  $path      Path
    * @param mixed   $value     Value to set
    * @param string  $delimiter Path delimiter
    */

    public static function set_path( & $array, $path, $value, $delimiter = NULL)
    {
        if ( ! $delimiter)
        {
            // Use the default delimiter
            $delimiter = Arr::$delimiter;
        }

        // Split the keys by delimiter
        $keys = explode($delimiter, $path);

        // Set current $array to inner-most array path
        while (count($keys) > 1)
        {
            $key = array_shift($keys);

            if (ctype_digit($key))
            {
                // Make the key an integer
                $key = (int) $key;
            }

            if ( ! isset($array[$key]))
            {
                $array[$key] = array();
            }

            $array = & $array[$key];
        }

        // Set key on inner-most array
        $array[array_shift($keys)] = $value;
    }
277
12 ноября 2011 года
arrjj
1.7K / / 26.01.2011
Цитата: onerror
Думаю, что eval принципиально медленнее чего угодно другого (но опять же вряд ли это будет заметно).



Неа по скорости отработки будет всё равно что просто выполнить строку $ret=$array[......]. А вто str_replace хз.

66K
12 ноября 2011 года
onerror
45 / / 05.07.2011
Цитата: Lone Wolf
что в этом коде не так?



я бы сказал, что в этом коде "не так" последние три строки :-). Лучше бы так:

 
Код:
echo "<pre>for: $time1 s\n";
echo "while: $time2 s\n";
echo "foreach: $time3 s\n</pre>";
274
12 ноября 2011 года
Lone Wolf
1.3K / / 26.11.2006
Цитата: onerror
я бы сказал, что в этом коде "не так" последние три строки :-). Лучше бы так:

 
Код:
echo "<pre>for: $time1 s\n";
echo "while: $time2 s\n";
echo "foreach: $time3 s\n</pre>";


:facepalm: ты еще скажи, что ты даный код в браузере заупскал. хотя судя по всему именно там.. :facepalm:

714
13 ноября 2011 года
clgs
226 / / 29.10.2008
Цитата: RussianSpy
foreach тут не нужен -он медленный
 
Код:
function getVal($array, $path)
{
  $path_array = explode('/',$path);
 
  for($i=0; $i<sizeof($path_array); $i++) $array = $array[$path_array[$i]];
  return $array;
}


=) А постоянно вычислять размер массива который в процессе цикла не меняется, увеличивает производительность?)))

13
14 ноября 2011 года
RussianSpy
3.0K / / 04.07.2006
Цитата: clgs
=) А постоянно вычислять размер массива который в процессе цикла не меняется, увеличивает производительность?)))


Фанат! Молодец. Я готов тебе рассказать как правильно строить храмы в мою честь и уже написал 10 заповедей. Будешь моим пророком, сынок

Специально для тебя рассказываю - записывай: нужно перед циклом создать переменную куда сохранишь размер массива. Писал я это в запаре после 30 часов без сна, опечатался. Молодец что заметил!

714
14 ноября 2011 года
clgs
226 / / 29.10.2008
Цитата: RussianSpy
Специально для тебя рассказываю - записывай: нужно перед циклом создать переменную куда сохранишь размер массива. Писал я это в запаре после 30 часов без сна, опечатался. Молодец что заметил!


Вы еще меня научите как пользоваться echo.

13
14 ноября 2011 года
RussianSpy
3.0K / / 04.07.2006
Цитата: clgs
Вы еще меня научите как пользоваться echo.



OFFTOPIC DETECTED:
Я тебя троллю, а ты поддаешься ;) Больше не буду. Давай завязывать с конфронтациями

15K
15 ноября 2011 года
hel
78 / / 10.11.2007
Подумал чуть и вот такой черновой вариант сделал. Использовал переменные переменных. Вроде работает. В раздумьях еще, его ли оставить, или сделать как во втором посте.

Код:
<?php

class Registry
{
    private $Data;
   
    private function parsePath($path)
    {
        $_path = explode("/", $path);
       
        $path_s = "";
       
        if(!$_path)
        {
            foreach($_path as $sub_path)
            {
                $path_s .= "[" . $sub_path . "]";
            }
        }
       
        return $path_s;
    }
   
    public function getVal($path)
    {
        $_path = "Data" . $this->parsePath($path);
        print $this->$_path;
    }
   
    public function setVal($path, $value)
    {
        $_path = "Data" . $this->parsePath($path);
        $this->$_path = $value;
    }
   
    public function addPath($path, $new_path)
    {
        $_path = "Data" . $this->parsePath($path);
        $this->$_path = $new_path;
    }
   
    public function delPath($path)
    {
        $_path = "Data" . $this->parsePath($path);
        unset($this->$_path);
    }
   
    public function dumpPath($path)
    {
        $_path = "Data" . $this->parsePath($path);
        print "<pre>" . var_export($this->$_path) . "</pre>";
    }
}

?>
66K
16 ноября 2011 года
onerror
45 / / 05.07.2011
Смотрел, смотрел на "черновой вариант" минут пять... Никак не мог поверить, что это вообще запустится. Попробовал:
 
Код:
$r = new Registry();
$r->setVal('a/b', 'c');
$r->setVal('c/d', 'E');
$r->getVal('a/b'); //=>E !!


Делайте уже "как во втором посте" :-)
15K
16 ноября 2011 года
hel
78 / / 10.11.2007
Цитата: onerror
Смотрел, смотрел на "черновой вариант" минут пять... Никак не мог поверить, что это вообще запустится. Попробовал:
 
Код:
$r = new Registry();
$r->setVal('a/b', 'c');
$r->setVal('c/d', 'E');
$r->getVal('a/b'); //=>E !!


Делайте уже "как во втором посте" :-)



Тоже задумывался об этом. Как-то некрасиво и несерьезно выглядит вариант с переменными переменных.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог