in_array () и многомерный массив

243

Я использую, in_array()чтобы проверить, существует ли значение в массиве, как показано ниже,

$a = array("Mac", "NT", "Irix", "Linux");
if (in_array("Irix", $a)) 
{
    echo "Got Irix";
}

//print_r($a);

но как насчет многомерного массива (ниже) - как я могу проверить это значение, существует ли оно в многомерном массиве?

$b = array(array("Mac", "NT"), array("Irix", "Linux"));

print_r($b);

или я не должен использовать, in_array()когда дело доходит до многомерного массива?

laukok
источник
1
Принятое решение прекрасно работает, но может привести к непредвиденным результатам при выполнении нестрогих сравнений из-за жонглирования типов в PHP. См .: stackoverflow.com/a/48890256/1579327
Паоло
1
как jwueller «s ответа и мой являются правильными ответами на ваш вопрос. Я предложил альтернативное решение, которое расширяет функции jwueller , чтобы избежать общей ошибки, связанной с жонглированием типов PHP при выполнении нестрогих сравнений.
Паоло
1
один лайнер:var_dump(array_sum(array_map(function ($tmp) {return in_array('NT',$tmp);}, $multiarray)) > 0);
Агниус Василяускас
1
@AgniusVasiliauskas умное решение, но есть проблемы, если массив первого уровня содержит элемент, который не является массивом, например:$multiarray = array( "Hello", array("Mac", "NT"), array("Irix", "Linux"));
Paolo
1
@Paolo Никто не мешает вам расширять анонимную функцию в соответствии с вашими потребностями - в этом случае добавьте проверку анонимной функции, если переменная $tmp- это массив с is_array()функцией. Если не массив - переходите по другому сценарию.
Агний Василяускас

Ответы:

473

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

function in_array_r($needle, $haystack, $strict = false) {
    foreach ($haystack as $item) {
        if (($strict ? $item === $needle : $item == $needle) || (is_array($item) && in_array_r($needle, $item, $strict))) {
            return true;
        }
    }

    return false;
}

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

$b = array(array("Mac", "NT"), array("Irix", "Linux"));
echo in_array_r("Irix", $b) ? 'found' : 'not found';
jwueller
источник
1
Спасибо. функция элегантна! любить это! Спасибо. Как я могу знать, что он возвращает true или false, поскольку мой экран показывает что-либо, когда я запускаю вашу функцию? Спасибо.
Лаукок
14
Я искал что-то, что сделало это, вы просто спасли меня от написания моего собственного :)
Лиам W
1
Работает отлично. Итак, как мы можем искать и отображать ключ массива? Например: $ b = array (1 => array ("Mac", "NT"), 3 => array ("Irix", "Linux"));
Рашад
2
@ D.Tate Code для StackOverflow лицензируется по cc by-sa 3.0 с обязательным указанием авторства (см. Нижний колонтитул страницы). Вы можете просто добавить комментарий с постоянной ссылкой на этот ответ.
jwueller
1
@blamb: Это очень намеренно. Это то, что делает функцию рекурсивной (следовательно _r, аналогичной print_r(), например). Он опускается во все вложенные массивы для поиска значения, пока не будет найдено больше массивов. Таким образом, вы можете искать в массивах произвольной сложности, а не только на двух уровнях.
jwueller
56

Если вы знаете, по какому столбцу вести поиск, вы можете использовать array_search () и array_column ():

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

    (1) => Array
        (
            ('uid') => '5465',
            ('name') => 'Stefanie Mcmohn',
            ('url') => 'urlof5465'
        ),

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

if(array_search('urlof5465', array_column($userdb, 'url')) !== false) {
    echo 'value is in multidim array';
}
else {
    echo 'value is not in multidim array';
}

Эта идея находится в разделе комментариев для array_search () в руководстве по PHP;

ethmz
источник
15
Вы также можете попробовать: in_array ('value', array_column ($ arr, 'active'))
экстро
1
Вам нужен PHP 5.5+ дляarray_column
meconroy
1
Можно ли получить uid сопоставленного суб-массива в этом примере? @ethmz
zipal_
это именно то, что я хочу
Джунед Ансари
Это прекрасно после того, как долго нашел это решение!
Рохан Ашик
54

Это тоже будет работать.

function in_array_r($item , $array){
    return preg_match('/"'.preg_quote($item, '/').'"/i' , json_encode($array));
}

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

if(in_array_r($item , $array)){
    // found!
}
NassimPHP
источник
3
Умно, мне это нравится. Интересно, на что похожа производительность по сравнению с foreachпетлей?
Джеймс
1
Работал как шарм.
призрак kemicofa
1
Не поймите меня неправильно, мне нравится этот подход для этого случая. Однако он вернет ложное положительное совпадение, когда json_encoding и $arrayимеет ассоциативный ключ, который совпадает $item. Не говоря уже о возможности непреднамеренного совпадения части строки, когда в самой строке есть двойные кавычки. Я бы доверял этой функции только в маленьких / простых ситуациях, таких как этот вопрос.
mickmackusa
Обратите внимание, что это не удастся, если $itemсодержит символы, которые испортили первый параметр (регулярное выражение)preg_match
Паоло
35

Это сделает это:

foreach($b as $value)
{
    if(in_array("Irix", $value, true))
    {
        echo "Got Irix";
    }
}

in_arrayработает только с одномерным массивом, поэтому вам нужно циклически проходить in_arrayпо каждому подмассиву и запускать на каждом

Как уже отмечали другие, это будет только для 2-мерного массива. Если у вас есть больше вложенных массивов, рекурсивная версия будет лучше. Смотрите другие ответы для примеров этого.

Алан Гелейнсе
источник
7
Однако это будет работать только в одном измерении. Вам нужно создать рекурсивную функцию, чтобы проверить каждую глубину.
metrobalderas
Я запустил код, но в нем есть ошибка - Ошибка разбора: ошибка разбора в C: \ wamp \ www \ 000_TEST \ php \ php.in_array \ index.php в строке 21 - если (in_array ("Irix", $ value) ) спасибо.
Laukok
@lauthiamkok: есть ) в конце упомянутой строки отсутствует.
jwueller
Спасибо, я исправил свой ответ. Вот что происходит, когда я печатаю слишком быстро и не перечитываю свой код.
Алан Гелейнсе
Вы всегда должны вызывать in_array()с третьим параметром, установленным в true. Проверьте здесь, почему: stackoverflow.com/questions/37080581/…
Андреас
25

если ваш массив такой

$array = array(
              array("name" => "Robert", "Age" => "22", "Place" => "TN"), 
              array("name" => "Henry", "Age" => "21", "Place" => "TVL")
         );

Использовать это

function in_multiarray($elem, $array,$field)
{
    $top = sizeof($array) - 1;
    $bottom = 0;
    while($bottom <= $top)
    {
        if($array[$bottom][$field] == $elem)
            return true;
        else 
            if(is_array($array[$bottom][$field]))
                if(in_multiarray($elem, ($array[$bottom][$field])))
                    return true;

        $bottom++;
    }        
    return false;
}

пример : echo in_multiarray("22", $array,"Age");

rynhe
источник
21
$userdb = Array
(
    (0) => Array
        (
            ('uid') => '100',
            ('name') => 'Sandra Shush',
            ('url') => 'urlof100'
        ),

    (1) => Array
        (
            ('uid') => '5465',
            ('name') => 'Stefanie Mcmohn',
            ('url') => 'urlof5465'
        ),

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

$url_in_array = in_array('urlof5465', array_column($userdb, 'url'));

if($url_in_array) {
    echo 'value is in multidim array';
}
else {
    echo 'value is not in multidim array';
}
Мукеш Гоял
источник
2
Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, как и / или почему он решает проблему, улучшит долгосрочную ценность ответа.
Дональд Дак
3
6 лет спустя он дал мне то, что мне нужно. array_column()
NappingRabbit
идеальный ответ для многомерного массива
Рошан Санхе
14

Великая функция, но это не работало для меня , пока я не добавил if($found) { break; }кelseif

function in_array_r($needle, $haystack) {
    $found = false;
    foreach ($haystack as $item) {
    if ($item === $needle) { 
            $found = true; 
            break; 
        } elseif (is_array($item)) {
            $found = in_array_r($needle, $item); 
            if($found) { 
                break; 
            } 
        }    
    }
    return $found;
}
Фернандо
источник
11

Для многомерных детей: in_array('needle', array_column($arr, 'key'))

Для одномерных детей: in_array('needle', call_user_func_array('array_merge', $arr))

Мохд Абдул Муджиб
источник
1
Ухоженная! Спасибо @ 9ksoft
Фаберест
И в отличие от array_column()метода, этот call_user_func_array('array_merge')метод также работает с основанными на индексе дочерними массивами, +1
6

Вы всегда можете сериализовать свой многомерный массив и сделать strpos:

$arr = array(array("Mac", "NT"), array("Irix", "Linux"));

$in_arr = (bool)strpos(serialize($arr),'s:4:"Irix";');

if($in_arr){
    echo "Got Irix!";
}

Различные документы для вещей, которые я использовал:


источник
1
Это неверно. Ваша функция также выдаст true, если строка поиска содержится в некотором значении массива (найдет «Irix» в «mytoll Irixus»).
mdunisch
Я исправил свой ответ. @ user3351722
таким способом можно решить проблему, когда больше нет одного (уникального хранилища), и он должен быть динамическим .. как этот $ in_arr = (bool) strpos (serialize ($ user_term_was_downloaded), s: 3: "tid"; s: 2: "» $ ценностно> TID.. '";');
Anees Hikmat Abu Hmiad
2
@ Я - я ... я не думаю, что кто-либо в Stack Overflow разместит код, если он не хочет, чтобы им делился. Не стесняйтесь использовать любой код на этом сайте для чего угодно. Я обычно добавляю комментарий на одну строку над фрагментом кода с надписью «Спасибо, переполнение стека», а затем вставляю URL, с которого я нашел код.
1
Интересный ответ, безусловно, работает в определенных ситуациях, но не во всех.
MKN Web Solutions
4

Начиная с PHP 5.6 есть лучше и чище для оригинального ответа решение:

С многомерным массивом, подобным этому:

$a = array(array("Mac", "NT"), array("Irix", "Linux"))

Мы можем использовать оператор splat :

return in_array("Irix", array_merge(...$a), true)

Если у вас есть строковые ключи, как это:

$a = array("a" => array("Mac", "NT"), "b" => array("Irix", "Linux"))

Вы должны будете использовать array_values, чтобы избежать ошибки Cannot unpack array with string keys:

return in_array("Irix", array_merge(...array_values($a)), true)
Фабьен Саллес
источник
2

Принятое решение (на момент написания) по jwueller

function in_array_r($needle, $haystack, $strict = false) {
    foreach ($haystack as $item) {
        if (($strict ? $item === $needle : $item == $needle) || (is_array($item) && in_array_r($needle, $item, $strict))) {
            return true;
        }
    }

    return false;
}

Совершенно правильно, но может иметь непреднамеренное поведение при слабом сравнении (параметр $strict = false ).

Из-за жонглирования типа PHP при сравнении значений разных типов

"example" == 0

и

0 == "example"

Оценивает, trueпотому что "example"приведен intи превращен в0 .

(См. Почему PHP считает 0 равным строке? )

Если это не желаемое поведение, может быть удобно привести числовые значения к строке перед выполнением нестрого сравнения:

function in_array_r($needle, $haystack, $strict = false) {
    foreach ($haystack as $item) {

        if( ! $strict && is_string( $needle ) && ( is_float( $item ) || is_int( $item ) ) ) {
            $item = (string)$item;
        }

        if (($strict ? $item === $needle : $item == $needle) || (is_array($item) && in_array_r($needle, $item, $strict))) {
            return true;
        }
    }

    return false;
}
Paolo
источник
1

Это первая функция такого типа, которую я нашел в руководстве по php для in_array . Функции в секциях комментариев не всегда самые лучшие, но если это не помогает, вы тоже можете посмотреть там :)

<?php
function in_multiarray($elem, $array)
    {
        // if the $array is an array or is an object
         if( is_array( $array ) || is_object( $array ) )
         {
             // if $elem is in $array object
             if( is_object( $array ) )
             {
                 $temp_array = get_object_vars( $array );
                 if( in_array( $elem, $temp_array ) )
                     return TRUE;
             }

             // if $elem is in $array return true
             if( is_array( $array ) && in_array( $elem, $array ) )
                 return TRUE;


             // if $elem isn't in $array, then check foreach element
             foreach( $array as $array_element )
             {
                 // if $array_element is an array or is an object call the in_multiarray function to this element
                 // if in_multiarray returns TRUE, than return is in array, else check next element
                 if( ( is_array( $array_element ) || is_object( $array_element ) ) && $this->in_multiarray( $elem, $array_element ) )
                 {
                     return TRUE;
                     exit;
                 }
             }
         }

         // if isn't in array return FALSE
         return FALSE;
    }
?>
Gazillion
источник
Решение elusive лучше, поскольку оно предназначено только для массивов
Gazillion
1

Вот мое предложение, основанное на решении json_encode () с:

  • опция без учета регистра
  • возвращая счет вместо истинного
  • где угодно в массивах (ключи и значения)

Если слово не найдено, оно все равно возвращает 0, равное ложному .

function in_array_count($needle, $haystack, $caseSensitive = true) {
    if(!$caseSensitive) {
        return substr_count(strtoupper(json_encode($haystack)), strtoupper($needle));
    }
    return substr_count(json_encode($haystack), $needle);
}

Надеюсь, поможет.

Meloman
источник
Обратите внимание, что эта функция также подходит для подстрок : ex 00в 10000или loв Hello. Кроме того, произойдет сбой, если стрелка содержит любой символ, который json_encodeубегает , например, двойные кавычки.
Паоло
Конечно, это зависит от того, что вы будете делать, но для меня это решение имеет быстрое выполнение и достаточно.
Меломан
1

Я считаю, что вы можете просто использовать array_key_exists :

<?php
$a=array("Mac"=>"NT","Irix"=>"Linux");
if (array_key_exists("Mac",$a))
  {
  echo "Key exists!";
  }
else
  {
  echo "Key does not exist!";
  }
?>
SrAxi
источник
1

Я искал функцию, которая позволила бы мне искать и строки и массивы (как иголку) в массиве (стог сена), поэтому я добавил к ответу @jwueller .

Вот мой код:

/**
 * Recursive in_array function
 * Searches recursively for needle in an array (haystack).
 * Works with both strings and arrays as needle.
 * Both needle's and haystack's keys are ignored, only values are compared.
 * Note: if needle is an array, all values in needle have to be found for it to
 * return true. If one value is not found, false is returned.
 * @param  mixed   $needle   The array or string to be found
 * @param  array   $haystack The array to be searched in
 * @param  boolean $strict   Use strict value & type validation (===) or just value
 * @return boolean           True if in array, false if not.
 */
function in_array_r($needle, $haystack, $strict = false) {
     // array wrapper
    if (is_array($needle)) {
        foreach ($needle as $value) {
            if (in_array_r($value, $haystack, $strict) == false) {
                // an array value was not found, stop search, return false
                return false;
            }
        }
        // if the code reaches this point, all values in array have been found
        return true;
    }

    // string handling
    foreach ($haystack as $item) {
        if (($strict ? $item === $needle : $item == $needle)
            || (is_array($item) && in_array_r($needle, $item, $strict))) {
            return true;
        }
    }
    return false;
}
FreshSnow
источник
0

Это тоже работает, создавая сначала новый одномерный массив из исходного.

$arr = array("key1"=>"value1","key2"=>"value2","key3"=>"value3");

foreach ($arr as $row)  $vector[] = $row['key1'];

in_array($needle,$vector);
Banzy
источник
0

Более короткая версия, для многомерных массивов, созданных на основе наборов результатов базы данных.

function in_array_r($array, $field, $find){
    foreach($array as $item){
        if($item[$field] == $find) return true;
    }
    return false;
}

$is_found = in_array_r($os_list, 'os_version', 'XP');

Вернется, если массив $ os_list содержит 'XP' в поле os_version.

andreszs
источник
0

Я нашел действительно небольшое простое решение:

Если ваш массив:

Array
(
[details] => Array
    (
        [name] => Dhruv
        [salary] => 5000
    )

[score] => Array
    (
        [ssc] => 70
        [diploma] => 90
        [degree] => 70
    )

)

тогда код будет выглядеть так:

 if(in_array("5000",$array['details'])){
             echo "yes found.";
         }
     else {
             echo "no not found";
          }
Дхрув Таккар
источник
0

Я использовал этот метод работает для любого количества вложенных и не требует взлома

<?php
    $blogCategories = [
        'programing' => [
            'golang',
            'php',
            'ruby',
            'functional' => [
                'Erlang',
                'Haskell'
            ]
        ],
        'bd' => [
            'mysql',
            'sqlite'
        ]
    ];
    $it = new RecursiveArrayIterator($blogCategories);
    foreach (new RecursiveIteratorIterator($it) as $t) {
        $found = $t == 'Haskell';
        if ($found) {
           break;
        }
    }
Старший Либре
источник
-1

Пожалуйста попробуйте:

in_array("irix",array_keys($b))
in_array("Linux",array_keys($b["irix"])

Я не уверен в необходимости, но это может работать для вашего требования

Sparco
источник
2
Как бы поиск ключей массива сделал что-нибудь? $bключи массива - это просто целые числа ... в этих массивах нет заданных ключей ... и array_keys($b["irix"])они просто выдадут ошибку, потому $b["irix"]что не существует.
Ben D
-1

что насчет array_search? кажется, это довольно быстро, чем foreach в соответствии с https://gist.github.com/Ocramius/1290076 ..

if( array_search("Irix", $a) === true) 
{
    echo "Got Irix";
}
уклоняющийся от работы человек
источник
на самом деле array_search не является рекурсивным, так что это не работает. Я хотел бы, потому что это так чисто и просто. php.net/manual/en/function.array-search.php
MatthewLee