PHP багатовимірний пошук масиву (пошук ключа за конкретним значенням)


114

У мене є цей багатовимірний масив. Мені потрібно його пошукати і повертати лише той ключ, який відповідає значенню "слизи". Я знаю, що є інші теми щодо пошуку багатовимірних масивів, але я насправді недостатньо розумію, щоб застосувати до своєї ситуації. Дуже дякую за будь-яку допомогу!

Тому мені потрібна така функція, як:

myfunction($products,'breville-one-touch-tea-maker-BTM800XL');
// returns 1

Ось масив:

$products = array (
1  => array(
        'name'          => 'The Breville One-Touch Tea Maker',
        'slug'          => 'breville-one-touch-tea-maker-BTM800XL',
        'shortname'     => 'The One-Touch Tea Maker',
        'listprice'     => '299.99',
        'price'         => '249.99',
        'rating'        => '9.5',
        'reviews'       => '81',
        'buyurl'        => 'http://www.amazon.com/The-Breville-One-Touch-Tea-Maker/dp/B003LNOPSG',
        'videoref1'     => 'xNb-FOTJY1c',
        'videoref2'     => 'WAyk-O2B6F8',
        'image'         => '812BpgHhjBML.jpg',
        'related1'      => '2',
        'related2'      => '3',
        'related3'      => '4',
        'bestbuy'       => '1',
        'quote'         => '',
        'quoteautor'    => 'K. Martino',
        ),

2  => array(
        'name'          => 'Breville Variable-Temperature Kettle BKE820XL',
        'slug'          => 'breville-variable-temperature-kettle-BKE820XL',
        'shortname'     => 'Variable Temperature Kettle',
        'listprice'     => '199.99',
        'price'         => '129.99',
        'rating'        => '9',
        'reviews'       => '78',
        'buyurl'        => 'http://www.amazon.com/Breville-BKE820XL-Variable-Temperature-1-8-Liter-Kettle/dp/B001DYERBK',
        'videoref1'     => 'oyZWBD83xeE',
        'image'         => '41y2B8jSKmwL.jpg',
        'related1'      => '3',
        'related2'      => '4',
        'related3'      => '5',
        'bestbuy'       => '1',
        'quote'         => '',
        'quoteautor'    => '',
        ),
);

Відповіді:


157

Дуже просто:

function myfunction($products, $field, $value)
{
   foreach($products as $key => $product)
   {
      if ( $product[$field] === $value )
         return $key;
   }
   return false;
}

6
Якщо ви використовуєте цю функцію в умовному операторі, вам потрібно зробити абсолютну перевірку типу, оскільки повернений ключ іноді може мати індекс [0]. Тож, якщо робити умовну перевірку, це має виглядати приблизно так: if (myfunction($array, 'field', 'value') !== FALSE )) // do something...
Енді Кук

159

Ще одне можливе рішення засноване на array_search()функції. Вам потрібно використовувати PHP 5.5.0 або вище.

Приклад

$userdb=Array
(
(0) => Array
    (
        (uid) => '100',
        (name) => 'Sandra Shush',
        (url) => 'urlof100'
    ),

(1) => Array
    (
        (uid) => '5465',
        (name) => 'Stefanie Mcmohn',
        (pic_square) => 'urlof100'
    ),

(2) => Array
    (
        (uid) => '40489',
        (name) => 'Michael',
        (pic_square) => 'urlof40489'
    )
);

$key = array_search(40489, array_column($userdb, 'uid'));

echo ("The key is: ".$key);
//This will output- The key is: 2

Пояснення

Функція array_search()має два аргументи. Перший - це значення, яке ви хочете шукати. Друге - там, де функція повинна шукати. Функція array_column()отримує значення елементів, які є ключовими 'uid'.

Підсумок

Таким чином, ви можете використовувати його як:

array_search('breville-one-touch-tea-maker-BTM800XL', array_column($products, 'slug'));

або, якщо вам зручніше:

// define function
function array_search_multidim($array, $column, $key){
    return (array_search($key, array_column($array, $column)));
}

// use it
array_search_multidim($products, 'slug', 'breville-one-touch-tea-maker-BTM800XL');

Оригінальний приклад (від xfoxawy) можна знайти на DOCS . Сторінка .
array_column()


Оновлення

Завдяки коментарю Ваеля мені було цікаво, тому я зробив простий тест, щоб виміряти ефективність використовуваного методу array_searchта запропонованого методу на прийнятій відповіді.

Я створив масив, який містив 1000 масивів, структура була такою (усі дані були рандомізовані):

[
      {
            "_id": "57fe684fb22a07039b3f196c",
            "index": 0,
            "guid": "98dd3515-3f1e-4b89-8bb9-103b0d67e613",
            "isActive": true,
            "balance": "$2,372.04",
            "picture": "http://placehold.it/32x32",
            "age": 21,
            "eyeColor": "blue",
            "name": "Green",
            "company": "MIXERS"
      },...
]

Я провів тест пошуку 100 разів, шукаючи різні значення для поля імені, а потім обчислив середній час у мілісекундах . Тут ви можете побачити приклад.

Результати полягали в тому, що запропонованому для цього відповіді методу потрібно було приблизно 2E-7, щоб знайти значення, тоді як прийнятий метод відповіді потребував приблизно 8E-7.

Як я вже говорив раніше, обидва рази досить сприятливі для програми, що використовує масив такого розміру. Якщо розмір сильно зростає, скажімо, 1М елементів, то і ця невелика різниця також буде збільшена.

Оновлення II

Я додав тест для методу, в основі array_walk_recursiveякого було зазначено деякі відповіді. Отриманий результат - правильний. І якщо ми зосередимось на продуктивності, то вона трохи гірша, ніж інші, перевірені на тесті . У тесті ви бачите, що це приблизно в 10 разів повільніше, ніж заснований на методі array_search. Знову ж таки, це не дуже актуальна різниця для більшості програм.

Оновлення III

Завдяки @mickmackusa за виявлення декількох обмежень щодо цього методу:

  • Цей метод вийде з ладу на асоціативних ключах.
  • Цей метод працюватиме лише на індексованих підрядах (починаючи з 0 і мають послідовно висхідні ключі).

Хтось знає виконання цього? Схоже, це в кінцевому рахунку буде повільніше, і все-таки знадобиться 5.5. Я не можу перевірити, коли я 5.4.
Vael Victus

Для тих, хто не розуміє: у php 7 цикли циклу швидші. Коли я змінив 5.6 у тому прикладі eval.in, array_search був трохи швидшим.
Vael Victus

розумний! Я робив щось подібне, використовуючи array_combine () з array_column (), щоб створити ще один масив, з якого захопити мій даних відомим ключем, але це більш елегантно.
Девід,

4
Використання array_search()з array_column()не працюватиме на вибірковому масиві ОП, оскільки починаються з клавіш subarray 1. Цей метод також вийде з ладу на асоціативних ключах. Цей метод працюватиме лише на індексованих підрядах (починаючи з 0та мають послідовно висхідні ключі). Причиною цього є те, що array_column()генеруватимуть нові індекси у поверненому масиві.
mickmackusa

цілком правильно @mickmackusa, я додав ваші знання у відповідь. Дякуємо за допомогу
Іван Родрігес Торрес

14

Цей метод класу може здійснювати пошук у масиві за кількома умовами:

class Stdlib_Array
{
    public static function multiSearch(array $array, array $pairs)
    {
        $found = array();
        foreach ($array as $aKey => $aVal) {
            $coincidences = 0;
            foreach ($pairs as $pKey => $pVal) {
                if (array_key_exists($pKey, $aVal) && $aVal[$pKey] == $pVal) {
                    $coincidences++;
                }
            }
            if ($coincidences == count($pairs)) {
                $found[$aKey] = $aVal;
            }
        }

        return $found;
    }    
}

// Example:

$data = array(
    array('foo' => 'test4', 'bar' => 'baz'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test1', 'bar' => 'baz3'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test',  'bar' => 'baz4'),
    array('foo' => 'test4', 'bar' => 'baz1'),
    array('foo' => 'test',  'bar' => 'baz1'),
    array('foo' => 'test3', 'bar' => 'baz2'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test4', 'bar' => 'baz1')
);

$result = Stdlib_Array::multiSearch($data, array('foo' => 'test4', 'bar' => 'baz1'));

var_dump($result);

Вироблять:

array(2) {
  [5]=>
  array(2) {
    ["foo"]=>
    string(5) "test4"
    ["bar"]=>
    string(4) "baz1"
  }
  [10]=>
  array(2) {
    ["foo"]=>
    string(5) "test4"
    ["bar"]=>
    string(4) "baz1"
  }
}

Привіт Fatalist stackoverflow.com/questions/40860030/… . Чи потрібно, будь ласка, уточнити це питання
KARTHI SRV

4

Використовуйте цю функцію:

function searchThroughArray($search,array $lists){
        try{
            foreach ($lists as $key => $value) {
                if(is_array($value)){
                    array_walk_recursive($value, function($v, $k) use($search ,$key,$value,&$val){
                        if(strpos($v, $search) !== false )  $val[$key]=$value;
                    });
            }else{
                    if(strpos($value, $search) !== false )  $val[$key]=$value;
                }

            }
            return $val;

        }catch (Exception $e) {
            return false;
        }
    }

і функція дзвінка.

print_r(searchThroughArray('breville-one-touch-tea-maker-BTM800XL',$products));

Гарна відповідь. Ви можете перевірити виконання вашої пропозиції на мою відповідь
Іван Родрігес Торрес

Відповіді, що стосуються лише коду, мають низьке значення в StackOverflow. Будь ласка, оновіть свою публікацію, щоб пояснити, як працює функція пошуку підстрокових листків у вузлах. Цей метод не розроблений спеціально для роботи, як просить ОП, тому важливо уточнити відмінності. Демо-посилання значно покращить розуміння читачів. Завжди публікуйте відповіді з наміром навчити ОП та широку аудиторію ЗО.
mickmackusa

1
function search($array, $key, $value) 
{ 
    $results = array(); 

    if (is_array($array)) 
    { 
        if (isset($array[$key]) && $array[$key] == $value) 
            $results[] = $array; 

        foreach ($array as $subarray) 
            $results = array_merge($results, search($subarray, $key, $value)); 
    } 

    return $results; 
} 

Відповіді, що стосуються лише коду, мають низьке значення в StackOverflow. Будь ласка, оновіть свою публікацію, щоб пояснити, як працює ваш рекурсивний метод, ситуації, коли це доречно, та ситуації, коли рекурсія непотрібна. Завжди публікуйте відповіді з наміром навчити ОП та широку аудиторію ЗО.
mickmackusa

1

Для наступного відвідувача, який приходить: використовуйте рекурсивну прогулянку масиву; він відвідує кожен "лист" у багатовимірному масиві. Ось для натхнення:

function getMDArrayValueByKey($a, $k) {
    $r = [];
    array_walk_recursive ($a, 
                          function ($item, $key) use ($k, &$r) {if ($key == $k) $r[] = $item;}
                          );
    return $r;
}

Нема проблем! просто щоб заощадити ваш час, якщо ви спробуєте відповісти josef, функція повертає масив з одним елементом. Ключ - потрібна відповідь :)
Іван Родрігес Торрес

Відповідь Івана Йозефа сильно відрізняється від цієї. Ви самі це перевірили. Я продовжую окуляру цю відповідь, і я не думаю, що вона може працювати, тому що array_walk_recursive не може бачити рівень. Для кожної клавіші першого рівня josef викликає strpos або перевіряє всі leafnodes. Бачите різницю?
mickmackusa

Звичайно @mickmackusa Але Ганс дає щось натхнення, відповідь не дає рішення буквально. Це потребує більш детальної розробки, як це робив Йозеф у відповіді. Але ви праві в тому, що ця відповідь не повністю вирішує проблему.
Іван Родрігес Торрес

1

Я б хотів зробити нижче, де $productsвласне масив, наведений у проблемі на самому початку.

print_r(
  array_search("breville-variable-temperature-kettle-BKE820XL", 
  array_map(function($product){return $product["slug"];},$products))
);

0

Спробуйте це

function recursive_array_search($needle,$haystack) {
        foreach($haystack as $key=>$value) {
            $current_key=$key;
            if($needle==$value['uid'] OR (is_array($value) && recursive_array_search($needle,$value) !== false)) {
                return $current_key;
            }
        }
        return false;
    }

Відповіді, що стосуються лише коду, мають низьке значення в StackOverflow. Будь ласка, оновіть свою публікацію, щоб пояснити, як працює ваш рекурсивний метод, ситуації, коли це доречно, та ситуації, коли рекурсія непотрібна. Завжди публікуйте відповіді з наміром навчити ОП та широку аудиторію ЗО. Ps Я думаю, що більшість розробників php віддадуть перевагу &&і ||замість, ANDі ORу вашому стані. Немає підстав заявляти current_key. Порівняння щодо $needleмає бути суворим.
mickmackusa
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.