如何从对象数组中通过对象属性查找条目?

223

数组看起来像:

[0] => stdClass Object
        (
            [ID] => 420
            [name] => Mary
         )

[1] => stdClass Object
        (
            [ID] => 10957
            [name] => Blah
         )
...

我有一个名为$v的整数变量。

如何选择包含对象且ID属性具有$v值的数组项?

13个回答

212
你可以迭代数组,搜索特定记录(在一次性搜索中可行),或者使用另一个关联数组构建一个哈希映射表。对于前者,像这样:
$item = null;
foreach($array as $struct) {
    if ($v == $struct->ID) {
        $item = $struct;
        break;
    }
}

请参考这个问题以及随后的回答,了解有关后者的更多信息- 按多个索引引用PHP数组


3
将$item设置为null是不必要的。 - dAm2K
36
哎呀,它在那里 :) 这是在数组中找不到所寻找的项目时使用的。或者,您可以使用 isset($item),但我更喜欢正确初始化变量。 - Phil
3
对于将关键值设置为字符串的用户,请使用 if($v == $struct["ID"]){...。 (翻译已尽量保持原意,使语言通俗易懂,没有包含其他解释或信息) - wbadart

106
$arr = [
  [
    'ID' => 1
  ]
];

echo array_search(1, array_column($arr, 'ID')); // prints 0 (!== false)

上面的代码会返回匹配元素的 索引,如果没有匹配则返回 false

要获取相应的元素,请执行类似以下操作:

$i = array_search(1, array_column($arr, 'ID'));
$element = ($i !== false ? $arr[$i] : null);

array_column 可以同时作用于由数组组成的数组和对象组成的数组。


5
不确定为什么这不是首选答案。是因为你调用了两个函数吗? - doz87
2
我想我来晚了 ;) 它的简洁性和可读性没有任何循环和中断,这使得它合理。但是我还没有对其进行基准测试。在PHP中,您有很多选项可以实现相同的功能。 - Tim
3
非常优雅的解决方案。在PHP 7中,也适用于对象数组。 对于PHP 5:array_search($object->id, array_map(function($object) { return $object->id; }, $objects)); 对于PHP 7:array_search($object->id, array_column($objects, 'id')); - Mike
3
这不是首选答案,因为提问者要求对象数组,而这个答案只处理纯数组。 - Dwza
13
不正确。这段代码可以处理对象数组/非扁平化数组。 - Tim
显示剩余5条评论

77

YurkamTim 是正确的。它只需要一个修改:

在 function($) 后,你需要通过 "use(&$searchedValue)" 提供对外部变量的指针,然后你就可以访问外部变量了。同时你也可以修改它。

$neededObject = array_filter(
    $arrayOfObjects,
    function ($e) use (&$searchedValue) {
        return $e->id == $searchedValue;
    }
);

3
你对修改的方法是正确的,而且这种方法很不错。但我进行了速度测试,与你直接迭代对象相比较,因为正如@phil所指出的,array_filter也是这样做的,结果发现这种方法慢了大约五倍。我的测试对象并不大,所以可能会更糟。 - Nicolai Grossherr
12
$searchedValue导入闭包作用域时,不需要使用&符号。仅在闭包内修改了$searchedValue时才需要使用&符号来创建一个引用。 - Stefan Gehrig
太酷了,我不知道 PHP 可以做那样的事情。我以为在函数中使用 global 是唯一共享数据的方法!但如果这确实很慢,那就有点遗憾了。:( - NoOne
15
TS要求一个单一的条目,而这段代码返回了一个数组。 - Pavel Vlasov
YurkaTim的答案已更新,包括use ($searchedValue)。正如StefanGehrig在评论中所说,除非需要修改$searchedValue,否则不需要使用&use (&$searchedValue) - ToolmakerSteve

41

我在这里找到了更优雅的解决方案适应问题可能会像这样:

$neededObject = array_filter(
    $arrayOfObjects,
    function ($e) use ($searchedValue) {
        return $e->id == $searchedValue;
    }
);

27
+1 但是 array_filter 返回一个数组,不会在找到第一个值后停止。 - Carlos Campderrós
嗯,这要看情况;) 如果我有几个项目的数组,我会更喜欢使用array_filter而不是手工循环,因为它是内置的php函数。 - YurkaTim
4
在函数内部无法识别$searchedValue,但在函数外可以识别。 - M. Ahmad Zafar
4
首先,这段代码无法正常工作,因为$searchedValue在闭包范围之外。其次,您认为这些数组方法是如何工作的?它们都在内部循环遍历数组。 - Phil
1
在多核时代,这个循环可以并行处理,但在其他编程环境中不一定。 - FloydThreepwood
4
要使用$searchedValue,需要编写function ($e) use ($searchedValue) { - Vilintritenmert

31

如果您需要多次查找,使用array_column进行重新索引可以节省时间:

$lookup = array_column($arr, NULL, 'id');   // re-index by 'id'

那么,您可以随意地使用$lookup[$id]


17

尝试

$entry = current(array_filter($array, function($e) use($v){ return $e->ID==$v; }));

这里有一个工作示例链接


它不会在找到第一个元素后停止,对吗? - yaugenka
@yaugenka - 正确的,它首先创建一个包含所有匹配项的数组。然后 current 返回第一个匹配项,如果没有匹配项则返回 false。[建议使用 === false 而不是 == false 来测试结果。] 在我看来,这种使用 current 有点晦涩难懂。另一方面,它是明确定义和记录的。 - ToolmakerSteve

14
class ArrayUtils
{
    public static function objArraySearch($array, $index, $value)
    {
        foreach($array as $arrayInf) {
            if($arrayInf->{$index} == $value) {
                return $arrayInf;
            }
        }
        return null;
    }
}

按照您的意愿使用它的方式可能是这样的:

ArrayUtils::objArraySearch($array,'ID',$v);

7

修复了@YurkaTim的一个小错误,您的解决方案对我有用,但需要添加use

为了在函数内使用$searchedValue,可以在函数参数function ($e) HERE后面添加use ($searchedValue)

array_filter函数只在返回条件为true时在$neededObject上返回。

如果$searchedValue是字符串或整数:

$searchedValue = 123456; // Value to search.
$neededObject = array_filter(
    $arrayOfObjects,
    function ($e) use ($searchedValue) {
        return $e->id == $searchedValue;
    }
);
var_dump($neededObject); // To see the output

如果$searchedValue是一个数组,我们需要与列表进行比较:

$searchedValue = array( 1, 5 ); // Value to search.
$neededObject  = array_filter(
    $arrayOfObjects,
    function ( $e ) use ( $searchedValue ) {
        return in_array( $e->term_id, $searchedValue );
    }
);
var_dump($neededObject); // To see the output

1
我觉得最后一行应该是 var_dump($neededObject); :) - Sliq

3

我有时喜欢使用array_reduce()函数进行搜索。它类似于array_filter(),但不影响搜索的数组,可以在同一对象数组上执行多个搜索。

$haystack = array($obj1, $obj2, ...); //some array of objects
$needle = 'looking for me?'; //the value of the object's property we want to find

//carry out the search
$search_results_array = array_reduce(
  $haystack,

  function($result_array, $current_item) use ($needle){
      //Found the an object that meets criteria? Add it to the the result array 
      if ($current_item->someProperty == $needle){
          $result_array[] = $current_item;
      }
      return $result_array;
  },
  array() //initially the array is empty (i.e.: item not found)
);

//report whether objects found
if (count($search_results_array) > 0){
  echo "found object(s): ";
  print_r($search_results_array[0]); //sample object found
} else {
  echo "did not find object(s): ";
}

1
你的条件语句中有一个拼写错误,你正在向results_array添加tot he。应该是这样的:if ($current_item->someProperty == $needle){ $result_array[] = $current_item; } - adrum
已调整。感谢 @adrum! - yuvilio
关于 *"它类似于 array_filter() 但不影响搜索的数组,允许您进行多次搜索"*:您似乎错误地认为 array_filter 修改了原始数组。它并没有。创建 $result_array 的函数恰好是 array_filter 已经执行的操作!AndreyP的后续答案 是使用 array_reduce 的有效方法;我看不出这个答案有什么用处 - 只需使用 AndreyP 的答案即可。如果你想在第一个项处停止,则编写一个在第一个项处停止的函数! - ToolmakerSteve

2

立即获取第一个值的方法:

最初的回答:

$neededObject = array_reduce(
    $arrayOfObjects,
    function ($result, $item) use ($searchedValue) {
        return $item->id == $searchedValue ? $item : $result;
    }
);

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