使用PHP多维数组按值搜索

473

我有一个数组,我想在其中搜索 uid 并获取数组的键。

示例

假设我们有以下二维数组:

$userdb = array(
    array(
        'uid' => '100',
        'name' => 'Sandra Shush',
        'pic_square' => 'urlof100'
    ),
    array(
        'uid' => '5465',
        'name' => 'Stefanie Mcmohn',
        'pic_square' => 'urlof100'
    ),
    array(
        'uid' => '40489',
        'name' => 'Michael',
        'pic_square' => 'urlof40489'
    )
);

调用函数 search_by_uid(100)(第一个用户的uid),应返回 0

调用函数 search_by_uid(40489),应返回 2

我尝试使用循环,但我想要一个更快执行的代码。


有趣的是,下划线(lowdash)库将此功能添加到JavaScript中... - ErichBSchulz
12
我编写了一个脚本来测试几个答案的性能。它生成一个包含500,000个数组的数组,并在其中搜索最后一个成员中的值。我将像已接受答案一样的函数与两个“array_column”单行答案进行比较。我对它们进行了修改,使其返回实际发现的数组,而不仅仅是键,因为通常这是我的用例。每种方法运行1000次的平均微延迟,函数方法得分为0.361,search-col为0.184,keys-col为0.189。 - Josh
23个回答

653
function searchForId($id, $array) {
   foreach ($array as $key => $val) {
       if ($val['uid'] === $id) {
           return $key;
       }
   }
   return null;
}

这个方法是可行的。你应该像下面这样调用它:

$id = searchForId('100', $userdb);

重要的是要知道,如果您使用 === 操作符进行比较,那么比较的类型必须完全相同,在这个例子中您需要搜索 string 或者只使用 == 而不是 ===

根据 angoru 的回答,在PHP的后续版本(>= 5.5.0)中,您可以使用一行代码。

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

这里是文档:http://php.net/manual/en/function.array-column.php


17
您还可以使用array_map替换array_column,以一行代码的形式在没有PHP 5.5的情况下完成。只需将array_column($userdb, 'uid')替换为array_map(function($v){return $v['uid'];},$userdb)即可。注意不要改变原文意思并尽量使翻译易懂。 - Jesse Green
2
是的,你说得对。自从PHP 5.3以来,Lambda函数就可用了。而更好的选择是array_search,不是吗? - Jakub Truneček
4
我认为原始解决方案(即“foreach”循环)会更快,因为一旦找到匹配项,它就会停止。新的解决方案需要遍历整个数组来提取“array_column”,然后第二次循环执行搜索(直到找到匹配项)。新的解决方案更易于阅读,更简洁,但OP特别提出性能是一个问题。 - BeetleJuice
如果我想搜索 uid = 100 AND name = Sandra Shush 的组合,我该怎么做呢?@Jakub Truneček - Balakumar B
7
请记住,如果您的数组键不是_0、1、2、3、n_(数字并按零开始的顺序),那么简短的答案无法起作用,因为使用array_column会重置键。 - dearsina
显示剩余7条评论

471

如果您使用的是(PHP 5 >= 5.5.0),那么您无需编写自己的函数来执行此操作,只需编写此行代码即可完成。

如果您只需要一个结果:

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

对于多个结果

$keys = array_keys(array_column($userdb, 'uid'), 40489);

如果您拥有如评论中所指出的关联数组,则可以使用以下方式创建:

$keys = array_keys(array_combine(array_keys($userdb), array_column($userdb, 'uid')),40489);

如果你正在使用 PHP < 5.5.0,你可以使用这个后移版本,感谢 Ramsey!

更新:我做了一些简单的基准测试,发现多结果形式似乎是最快的,甚至比 Jakub 的自定义函数还要快!


如果我要搜索的值(在本例中为40489)出现多次,而我想获取它出现的所有键,该怎么办? - Dimitris Papageorgiou
如果数组中出现了多个值为40489的元素,该函数是否会返回一个键的数组...?? @angoru - jishan
3
当$userdb中的键不以0, 1, 2等开头时,这对我没有起作用,比如键是1234、4566等。array_search后得到的键始终是0、1、2等等。 - Kaushtuv
4
这段代码无法在关联数组中使用,但你可以通过以下方式解决:array_search(40489, array_combine(array_keys($userdb), array_column($userdb, 'uid')))它将把关联数组转换为索引数组进行搜索。 - John Mellor
1
注意:如果没有找到匹配项,第一条语句将返回“false”,接下来的两条语句将返回一个空数组“[]”。 - Nabi K.A.Z.
显示剩余10条评论

59

在PHP的后续版本中(>=5.5.0),您可以使用这个一行代码:

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

7
将array_column的结果放入特定变量中,避免对数组中的每个结果都调用array_column。 - Maykonn

35

看起来 array_filter 将是解决这个问题的合适方案...

$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'
        )
);

PHP 代码

<?php 
$search = 5465;
$found = array_filter($userdb,function($v,$k) use ($search){
  return $v['uid'] == $search;
},ARRAY_FILTER_USE_BOTH); // With latest PHP third parameter is optional.. Available Values:- ARRAY_FILTER_USE_BOTH OR ARRAY_FILTER_USE_KEY  

$values= print_r(array_values($found));
$keys =  print_r(array_keys($found)); 

显示错误:语法错误,意外的' =>'(T_DOUBLE_ARROW),期望';' - Shihas
请问您能否提供更多信息,比如是哪一行代码、您的代码以及数组结构。 - BEJGAM SHIVA PRASAD
@Shihas,我更新了答案,我相信问题会得到解决。 - BEJGAM SHIVA PRASAD
1
我认为这是保留键的返回整个结果数组的正确解决方案。在 PHP >= 7 中,更短的方法是:array_filter($userdb, fn ($v) => $v['uid'] == $search)。你甚至不需要将变量传递给回调函数。请查看 https://www.php.net/manual/es/functions.arrow.php。 - Luciano Fantuzzi

33

在Jakub的优秀回答的基础上,这里提供了更加通用的搜索方法,可以允许指定关键字(不仅限于uid):

function searcharray($value, $key, $array) {
   foreach ($array as $k => $val) {
       if ($val[$key] == $value) {
           return $k;
       }
   }
   return null;
}

用法:$results = searcharray('搜索值', 搜索键, $数组);


22
我知道这个问题已经有答案了,但我在我的代码中使用了它并进行了一些扩展,这样你就不必仅通过uid搜索。我想为任何可能需要该功能的人分享它。
以下是我的示例,请注意这是我的第一个答案。我去掉了参数数组,因为我只需要搜索一个特定的数组,但你可以很容易地添加它。我想要搜索的内容不仅仅是uid。
此外,在我的情况下,有可能根据其他字段进行搜索并返回多个键作为结果,这些键可能不是唯一的。
 /**
     * @param array multidimensional 
     * @param string value to search for, ie a specific field name like name_first
     * @param string associative key to find it in, ie field_name
     * 
     * @return array keys.
     */
     function search_revisions($dataArray, $search_value, $key_to_search) {
        // This function will search the revisions for a certain value
        // related to the associative key you are looking for.
        $keys = array();
        foreach ($dataArray as $key => $cur_value) {
            if ($cur_value[$key_to_search] == $search_value) {
                $keys[] = $key;
            }
        }
        return $keys;
    }

后来,我写了这个程序,让我能够搜索另一个值和关联键。因此,我的第一个例子允许您在任何特定的关联键中搜索值,并返回所有匹配项。
这个第二个例子向您展示了如何在特定的关联键(first_name)中找到一个值(“Taylor”)并且在另一个关联键(employed)中找到另一个值(true),并返回所有匹配项(名字为'Taylor'且已雇用的人的键)。
/**
 * @param array multidimensional 
 * @param string $search_value The value to search for, ie a specific 'Taylor'
 * @param string $key_to_search The associative key to find it in, ie first_name
 * @param string $other_matching_key The associative key to find in the matches for employed
 * @param string $other_matching_value The value to find in that matching associative key, ie true
 * 
 * @return array keys, ie all the people with the first name 'Taylor' that are employed.
 */
 function search_revisions($dataArray, $search_value, $key_to_search, $other_matching_value = null, $other_matching_key = null) {
    // This function will search the revisions for a certain value
    // related to the associative key you are looking for.
    $keys = array();
    foreach ($dataArray as $key => $cur_value) {
        if ($cur_value[$key_to_search] == $search_value) {
            if (isset($other_matching_key) && isset($other_matching_value)) {
                if ($cur_value[$other_matching_key] == $other_matching_value) {
                    $keys[] = $key;
                }
            } else {
                // I must keep in mind that some searches may have multiple
                // matches and others would not, so leave it open with no continues.
                $keys[] = $key;
            }
        }
    }
    return $keys;
}

函数的使用

$data = array(
    array(
        'cust_group' => 6,
        'price' => 13.21,
        'price_qty' => 5
    ),
    array(
        'cust_group' => 8,
        'price' => 15.25,
        'price_qty' => 4
    ),
    array(
        'cust_group' => 8,
        'price' => 12.75,
        'price_qty' => 10
    )
);

$findKey = search_revisions($data,'8', 'cust_group', '10', 'price_qty');
print_r($findKey);

结果

Array ( [0] => 2 ) 

14

您可以通过两个函数的组合来实现此操作,array_searcharray_column

$search_value = '5465';
$search_key   = 'uid';
$user = array_search($search_value, array_column($userdb, $search_key));

print_r($userdb[$user]);

5465 是你想要搜索的用户ID,uid 是包含用户ID的键,$userdb 是在问题中定义的数组。

参考资料:

php.net 上的 array_search

php.net 上的 array_column


10
这里有一句话与之相同:

$pic_square = $userdb[array_search($uid,array_column($userdb, 'uid'))]['pic_square'];

10
我修改了下面描述函数array_search的一个例子。函数searchItemsByKey从多维数组(N级)中按$key返回所有值。也许对某些人有用。示例:
 $arr = array(
     'XXX'=>array(
               'YYY'=> array(
                    'AAA'=> array(
                          'keyN' =>'value1'
                   )
               ),
              'ZZZ'=> array(
                    'BBB'=> array(
                          'keyN' => 'value2'
                   )
               )
              //.....
           )
);


$result = searchItemsByKey($arr,'keyN');

print '<pre>';
print_r($result);
print '<pre>';
// OUTPUT
Array
(
  [0] => value1
  [1] => value2
)

功能代码:

function searchItemsByKey($array, $key)
{
   $results = array();

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

    foreach ($array as $sub_array)
        $results = array_merge($results, searchItemsByKey($sub_array, $key));
  }

 return  $results;
}

4

尽管这是一个老问题并且已经有了一个被接受的答案,但我想建议对被接受的答案进行一些修改。首先,我同意这个被接受的答案在这里是正确的。

function searchArrayKeyVal($sKey, $id, $array) {
   foreach ($array as $key => $val) {
       if ($val[$sKey] == $id) {
           return $key;
       }
   }
   return false;
}

将预设的“uid”替换为函数中的参数,现在调用下面的代码意味着您可以在多个数组类型中使用一个函数。虽然变化很小,但这使得结果略有不同。

    // Array Data Of Users
$userdb = array (
    array ('uid' => '100','name' => 'Sandra Shush','url' => 'urlof100' ),
    array ('uid' => '5465','name' => 'Stefanie Mcmohn','url' => 'urlof100' ),
    array ('uid' => '40489','name' => 'Michael','url' => 'urlof40489' ),
);

// Obtain The Key Of The Array
$arrayKey = searchArrayKeyVal("uid", '100', $userdb);
if ($arrayKey!==false) {
    echo "Search Result: ", $userdb[$arrayKey]['name'];
} else {
    echo "Search Result can not be found";
}

PHP Fiddle Example


另一个我使用SOF的原因是更容易通过谷歌搜索找到自己的代码或者我记得的东西。对于我自己的公共代码库,点赞加一。 - Angry 84
顺便提一下,你将结果设置为 null,然后在代码中将其与 false 进行比较。 - Taha Paksu
已进行更正,使用返回false代替,但在检查布尔值时,使用null可能更好。 - Angry 84

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