in_array()和多维数组

287

我使用 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()函数?


1
已接受的解决方案在进行非严格比较时可能会导致意外结果,这是由于 PHP 的类型转换。请参见:https://dev59.com/Hm855IYBdhLWcg3w0H53#48890256 - Paolo
@Paolo 谢谢你的评论。那么解决办法是什么呢?是你刚刚发表的回答吗? - Run
1
我的答案和jwueller的答案都是你问题的正确答案。我提出了一种替代方案,扩展了jwueller的函数,以避免PHP在进行非严格比较时的常见陷阱。 - Paolo
1
var_dump(array_sum(array_map(function ($tmp) {return in_array('NT',$tmp);}, $multiarray)) > 0); 的一句话代码。 - Agnius Vasiliauskas
1
@AgniusVasiliauskas 聪明的解决方案,但如果第一级数组包含一个不是数组的项,则存在问题,例如:$multiarray = array( "Hello", array("Mac", "NT"), array("Irix", "Linux")); - Paolo
1
@Paolo 没有人阻止您根据自己的需求扩展匿名函数 - 在这种情况下,可以在匿名函数中使用 is_array() 函数检查变量 $tmp 是否为数组。如果不是数组,则继续执行不同的方案。 - Agnius Vasiliauskas
24个回答

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;
}

2

我认为现在你可以直接使用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!";
  }
?>

1

这是我在php手册中找到的第一个此类函数。注释部分的函数并不总是最好的选择,但如果它不能解决问题,你也可以在那里找找 :)

<?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;
    }
?>

elusive的解决方案更好,因为它只用于数组。 - Gazillion

1
我正在寻找一个函数,可以让我在数组(堆栈)中作为 needle 搜索字符串和数组。因此,我添加到了 @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;
}

1
这里是基于json_encode()解决方案的建议,包括:
  • 不区分大小写选项
  • 返回计数而不是true
  • 在数组中的任何位置(键和值)

如果未找到单词,则仍将返回0等同于false

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);
}

希望它有所帮助。

请注意,此函数也会匹配子字符串:例如将 00 匹配为 10000 或将 lo 匹配为 Hello。此外,如果待查找的字符串包含任何 json_encode 转义的字符(如双引号),则该函数将失败。 - Paolo
当然,这取决于你要做什么,但对我来说,这个解决方案执行速度快且足够。 - Meloman

1
我使用的这种方法适用于任意数量的嵌套,无需进行破解。
<?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;
        }
    }

0

许多这样的搜索通常是为了在记录列表中查找内容,正如一些人指出的那样,这实际上是一个二维数组。

这适用于具有统一键集的记录列表(例如从数据库中获取的记录列表等)。

为了完整起见,这个结构包括了'in_array'和'key_exists'风格的函数。这两个函数都返回一个简单的true/false布尔值。

记录的二维数组示例...

$records array:

  [0] => Array
    (
        [first_name] => Charlie
        [last_name] => Brown
    )
  [1] => Array
    (
        [first_name] => Fred
        [last_name] => Sanford
    )

函数:

function in_multidimensional_array($array, $column_key, $search) { 
   return in_array($search, array_column($array, $column_key)); 
}

function multidimensional_array_key_exists($array, $column_key) { 
   return in_array($column_key, array_keys(array_shift($array))); 
}

测试:

var_dump(in_multidimensional_array($records, 'first_name', 'Charlie')); // true

var_dump(multidimensional_array_key_exists($records, 'first_name')); // true

0

我发现以下解决方案代码不是很干净,但它能够运行。它被用作递归函数。

function in_array_multi( $needle, $array, $strict = false ) {
  foreach( $array as $value ) { // Loop thorugh all values
    // Check if value is aswell an array
    if( is_array( $value )) {
      // Recursive use of this function
      if(in_array_multi( $needle, $value )) {
        return true; // Break loop and return true
      }
    } else {
      // Check if value is equal to needle
      if( $strict === true ) {
        if(strtolower($value) === strtolower($needle)) {
          return true; // Break loop and return true
        }
      }else {
        if(strtolower($value) == strtolower($needle)) {
          return true; // Break loop and return true
        }
      }
    }
  }

  return false; // Nothing found, false
}

0

它也可以通过首先从原始数组创建一个新的一维数组来实现。

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

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

in_array($needle,$vector);

0
请尝试以下操作:
in_array("irix",array_keys($b))
in_array("Linux",array_keys($b["irix"])

我不确定是否需要,但这可能符合您的要求。


2
搜索数组键有什么作用?$b的数组键只是整数...这些数组中没有指定的键...而且array_keys($b["irix"])会抛出一个错误,因为$b["irix"]不存在。 - Ben D

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接