Быстрый способ извлечь части массива? - PullRequest
0 голосов
/ 18 ноября 2009

У меня большой массив в PHP.

Содержит строки, которые разбиты на категории с помощью подчеркивания:

category1_property
category1_category2_category3
category2_category3_category4_category5

У меня есть функция с именем

array get_values($prefix) 

, который возвращает все значения массива, которые начинаются с данного префикса, например

get_values("category2_category3_");

Эта функция foreach () проходит через весь массив каждый раз, собирая все строки, начинающиеся с префикса, то есть просто

foreach ($my_array as $line)
 if (substr($line, 0, strlen($prefix)) == $prefix)) 
  array_push ($result, $line);

Мне плохо от такой производительности, особенно от того, что эта операция выполняется десятки раз за один запрос.

Кто-нибудь знает способ ускорить это, не прибегая к совершенно другому способу хранения данных?

Использование базы данных может быть быстрым и умным, но я бы хотел этого избежать. Данные поступают из файла, и я не могу перенести их в базу данных.

Предварительная сортировка или разбиение конструкции на многомерный массив или объект не вариант, потому что мне иногда нужно запросить части имени категории (например, "category1_ca *")

Заранее спасибо за любой вклад.

Ответы [ 5 ]

1 голос
/ 18 ноября 2009

Вы действительно ограничили возможности! Несмотря на это, я думаю, что предварительное разделение данных может быть способом пойти. Рассмотрим:

префиксы 'cat1_cat2_cat3_dog'='fido', 'cat1_cat2_cat3_fish'='goldie', 'cat1_cat2_cat3_frog'='kermit становятся

$arr[cat1][cat2][cat3][dog]=fido
$arr[cat1][cat2][cat3][fish]=goldie
$arr[cat1][cat2][cat3][frog]=kermit

Если вы хотите все с префиксом cat1_cat2:

$arr['cat1']['cat2']=array('cat3'=>array('dog'=>'fido','fish'=>'goldie'));

Если вы хотите все с префиксом cat1_cat2_cat3_f*, вам нужно искать только последний термин в $arr['cat1']['cat2']['cat3']:

$matches=preg_grep("/^f/",array_keys($arr['cat1']['cat2']['cat3']));
foreach($matches as $k){
   $results[]=$arr['cat1']['cat2]['cat3'][$k];
}
1 голос
/ 18 ноября 2009

Мне непонятно, как должна соответствовать функция get_values ​​- в любом случае, это может быть дружественное к производительности решение, которое вы ищете?

function get_values($prefix) {
    $included_array_from_file = array ( "category1_property", "category1_category2_category3", "category2_category3_category4_category5");

    foreach($included_array_from_file as $val) {
        if(strpos($val,$prefix)===0) {
            $out[] = $val;
        }
    }
    return $out;
}

print_r( get_values("category2_category3_") );

Выход:
Array ( [0] => category2_category3_category4_category5 )

UPDATE:

Вам нужно посчитать, сколько раз "category2_category3_" встречается в строке, верно? В этом случае я предлагаю вам создать многомерный массив для полной строки и сосчитать каждое вхождение, как показано в этом примере: (Обратите внимание, что пример только иллюстрирует, как это можно сделать - пример в настоящее время терпит неудачу, как я не знаете, как построить многомерный массив на лету, вам может потребоваться вызвать другую функцию «создания массива» при добавлении элементов в массив.)

Сбой («Невозможно использовать скалярное значение в качестве массива») - не знаю, как это сделать.

$data = array("category1_property", "category1_category2_category3", "category2_category3_category4_category5");
$counter = array();
foreach($data as $val) {
    foreach(explode(":",$val) as $val2) {
        // Now, create a multi-dimensional array with the category items as keys and increment the value by one for each item in the string, as in this example:
        // "category2_category3_category4_category5" ... turns into:
        // $counter[category2] += 1;
        // $counter[category2][category3] += 1;
        // $counter[category2][category3][category4] += 1;
        // $counter[category2][category3][category4][category5] += 1;
    }
}

Использование по назначению:

echo $counter[category2][category3];
1 голос
/ 18 ноября 2009

Я думаю, что вы ищете preg_grep

1 голос
/ 18 ноября 2009

Для эффективного по времени доступа, я думаю, самое простое решение - сортировка массива и использование модифицированного варианта алгоритма двоичного поиска , чтобы найти нижнюю и верхнюю границы массива, соответствующие вашему запросу. Это работает, потому что строки с одинаковыми префиксами всегда сортируются последовательно.

Если у вас есть этот диапазон, выборка соответствующих элементов является простым циклом for.

Очевидно, что это не тривиальная задача, поэтому не тратьте впустую время на это, если только действительно не является проблемой производительности. Преждевременная оптимизация, вы знаете тренировку ...

0 голосов
/ 18 ноября 2009

Или вы можете использовать анонимную функцию с array_filter ():

function get_values($arr, $str)
{
    $func = create_function('$item', 'return (strpos($item, "' . $str . '") === 0);');
    return array_filter($arr, $func);
}

$prefix = 'category1';
$result = get_values($my_array, $prefix);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...