Как выполнить поиск по key => значение в многомерном массиве в PHP



6 Answers

Как насчет версии SPL ? Это спасет вас от ввода:

// I changed your input example to make it harder and
// to show it works at lower depths:

$arr = array(0 => array('id'=>1,'name'=>"cat 1"),
             1 => array(array('id'=>3,'name'=>"cat 1")),
             2 => array('id'=>2,'name'=>"cat 2")
);

//here's the code:

    $arrIt = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr));

 foreach ($arrIt as $sub) {
    $subArray = $arrIt->getSubIterator();
    if ($subArray['name'] === 'cat 1') {
        $outputArray[] = iterator_to_array($subArray);
    }
}

Замечательно то, что в основном один и тот же код будет перебирать через каталог для вас, используя рекурсивныйDirectoryIterator вместо рекурсивногоArrayIterator. SPL - это роксор.

Единственным обломком SPL является то, что он плохо документирован в Интернете. Но несколько книг PHP посвящены некоторым полезным деталям, особенно Pro PHP; и вы можете, вероятно, google и получить дополнительную информацию.

Question

Есть ли какой-либо быстрый способ получить все подмассивы, где пара ключевых значений была найдена в многомерном массиве? Я не могу сказать, насколько глубоким будет массив.

Простой пример массива:

$arr = array(0 => array(id=>1,name=>"cat 1"),
             1 => array(id=>2,name=>"cat 2"),
             2 => array(id=>3,name=>"cat 1")
);

Когда я ищу ключ = имя и значение = "cat 1", функция должна возвращать:

array(0 => array(id=>1,name=>"cat 1"),
      1 => array(id=>3,name=>"cat 1")
);

Я думаю, функция должна быть рекурсивной, чтобы перейти на самый глубокий уровень.




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

Его опубликованная функция работает нормально, но мне пришлось оптимизировать этот сценарий для обработки набора результатов в 12 000 строк. Функция выполняла вечные 8 секунд, чтобы пройти через все записи, waaaaaay слишком долго.

Я просто нуждался в функции STOP для поиска и возврата, когда совпадение найдено. То есть, если вы ищете client_id, мы знаем, что у нас есть только один в наборе результатов, и как только мы найдем customer_id в многомерном массиве, мы хотим вернуться.

Вот оптимизированная по скорости (и значительно упрощенная) версия этой функции для всех, кто в ней нуждается. В отличие от другой версии, она может обрабатывать только одну глубину массива, не рекурсивно и не позволяет слить несколько результатов.

// search array for specific key = value
public function searchSubArray(Array $array, $key, $value) {   
    foreach ($array as $subarray){  
        if (isset($subarray[$key]) && $subarray[$key] == $value)
          return $subarray;       
    } 
}

Это сбило задачу, чтобы соответствовать 12 000 записей за 1,5 секунды. Все еще очень дорого, но гораздо более разумно.




http://snipplr.com/view/51108/nested-array-search-by-value-or-key/

<?php

//PHP 5.3

function searchNestedArray(array $array, $search, $mode = 'value') {

    foreach (new RecursiveIteratorIterator(new RecursiveArrayIterator($array)) as $key => $value) {
        if ($search === ${${"mode"}})
            return true;
    }
    return false;
}

$data = array(
    array('abc', 'ddd'),
    'ccc',
    'bbb',
    array('aaa', array('yyy', 'mp' => 555))
);

var_dump(searchNestedArray($data, 555));



Мне нужно было что-то подобное, но искать многомерный массив по значению ... Я взял пример Джона и написал

function _search_array_by_value($array, $value) {
        $results = array();
        if (is_array($array)) {
            $found = array_search($value,$array);
            if ($found) {
                $results[] = $found;
            }
            foreach ($array as $subarray)
                $results = array_merge($results, $this->_search_array_by_value($subarray, $value));
        }
        return $results;
    }

Надеюсь, это поможет кому-то :)




function findKey($tab, $key){
    foreach($tab as $k => $value){ 
        if($k==$key) return $value; 
        if(is_array($value)){ 
            $find = findKey($value, $key);
            if($find) return $find;
        }
    }
    return null;
}



Вот решение:

<?php
$students['e1003']['birthplace'] = ("Mandaluyong <br>");
$students['ter1003']['birthplace'] = ("San Juan <br>");
$students['fgg1003']['birthplace'] = ("Quezon City <br>");
$students['bdf1003']['birthplace'] = ("Manila <br>");

$key = array_search('Delata Jona', array_column($students, 'name'));
echo $key;  

?>



Будьте осторожны с алгоритмами линейного поиска (приведенные выше линейными) в многомерных массивах, поскольку они усложняют сложность, так как ее глубина увеличивает количество итераций, необходимых для прохождения по всему массиву. Например:

array(
    [0] => array ([0] => something, [1] => something_else))
    ...
    [100] => array ([0] => something100, [1] => something_else100))
)

потребовалось бы всего 200 итераций, чтобы найти то, что вы ищете (если игла была в [100] [1]), с подходящим алгоритмом.

Линейные алгоритмы в этом случае выполняются в O (n) (общее количество элементов в целом массиве), это плохо, миллион записей (например, массив 1000x100x10) потребует в среднем 500 000 итераций, чтобы найти иглу. Также, что произойдет, если вы решите изменить структуру вашего многомерного массива? И PHP выработал бы рекурсивный алгоритм, если бы ваша глубина была больше 100. Информатика может сделать лучше:

По возможности всегда используйте объекты вместо многомерных массивов:

ArrayObject(
   MyObject(something, something_else))
   ...
   MyObject(something100, something_else100))
)

и примените пользовательский интерфейс и функцию компаратора для их сортировки и поиска:

interface Comparable {
   public function compareTo(Comparable $o);
}

class MyObject implements Comparable {
   public function compareTo(Comparable $o){
      ...
   }
}

function myComp(Comparable $a, Comparable $b){
    return $a->compareTo($b);
}

Вы можете использовать uasort() для использования пользовательского компаратора, если вы чувствуете себя авантюристом, вы должны реализовать свои собственные коллекции для своих объектов, которые могут их сортировать и управлять ими (я всегда расширяю ArrayObject, чтобы включить функцию поиска, по крайней мере).

$arrayObj->uasort("myComp");

Когда они сортируются (uasort - это O (n log n), что так же хорошо, как и по произвольным данным), двоичный поиск может выполнять операцию в O (log n), т. Е. Миллион записей занимает всего 20 итераций поиск. Насколько мне известно, бинарный поиск не выполняется в PHP ( array_search() использует естественное упорядочение, которое работает с объектными ссылками, а не их свойствами), вы должны реализовать это свое я, как я.

Этот подход более эффективен (больше нет глубины) и, что более важно, универсален (при условии, что вы обеспечиваете сопоставимость с использованием интерфейсов), поскольку объекты определяют, как они сортируются, поэтому вы можете бесконечно перерабатывать код. Гораздо лучше =)




Related