PHP - найти запись по свойству объекта из массива объектов

174

Массив выглядит так:

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

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

И у меня есть целочисленная переменная с именем $v.

Как я могу выбрать запись массива, которая имеет объект, где IDсвойство имеет $vзначение?

Alex
источник

Ответы:

189

Вы либо выполняете итерацию массива, ища конкретную запись (хорошо, только при поиске только один раз), либо создаете хэш-карту, используя другой ассоциативный массив.

Для первых что-то вроде этого

$item = null;
foreach($array as $struct) {
    if ($v == $struct->ID) {
        $item = $struct;
        break;
    }
}

См. Этот вопрос и последующие ответы для получения дополнительной информации о последнем - Ссылочный массив PHP по нескольким индексам

Фил
источник
3
установка $ item в null не требуется.
dAm2K
32
К сожалению, это так :) То есть, если искомый элемент отсутствует в массиве. Кроме того, вы можете использовать, isset($item)но я предпочитаю правильно инициализировать переменные
Фил
3
Для тех из вас, у кого для ключей заданы строковые значенияif($v == $struct["ID"]){...
wbadart
67

Юркам Тим прав. Нужна только модификация:

После функции ($) вам нужен указатель на внешнюю переменную с помощью «use (& $ seekValue)», а затем вы можете получить доступ к внешней переменной. Также вы можете изменить его.

$neededObject = array_filter(
    $arrayOfObjects,
    function ($e) use (&$searchedValue) {
        return $e->id == $searchedValue;
    }
);
Даниэль Хардт
источник
2
Вы правы насчет модификации, и это своего рода аккуратный метод, но я проверил скорость по сравнению с итерацией по объекту - самостоятельно, потому что, как указал @phil, array_filter делает это тоже - и этот метод занимает около пяти раз дольше. Мой тестовый объект не большой, так что может быть еще хуже.
Николай
9
&Не требуется при ввозе $searchedValueв сферу закрытия. &Используется для создания ссылки , которая необходима , только если $searchedValueбыл изменен внутри затвора.
Стефан Гериг
Это классно. Я не знал, что PHP может делать такие вещи. Я думал, что использование globalбыло единственным, чтобы делиться данными в функциях! Но жаль, если это действительно медленно. :(
NoOne
13
TS запрашивает одну запись, этот код возвращает массив.
Павел Власов
57
$arr = [
  [
    'ID' => 1
  ]
];

echo array_search(1, array_column($arr, 'ID')); // prints 0 (!== false)
Тим
источник
3
Не уверен, почему это не самый лучший ответ. Это потому, что вы вызываете две функции?
doz87
1
Я думаю, что я опоздал на вечеринку;) Его нехватка и удобочитаемость без каких-либо петель и разрывов сделали бы это разумным. Но пока не тестировали. У вас есть много вариантов в PHP, чтобы достичь того же.
Тим
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'));
Майк
3
Это не предпочтительный ответ, потому что операционная система запрашивает массив объектов, и этот ответ обрабатывает только чистые массивы.
Двза
8
это не правильно. этот код обрабатывает массив объектов /
Тим
31

Я нашел более элегантное решение здесь . Адаптированный к вопросу это может выглядеть так:

$neededObject = array_filter(
    $arrayOfObjects,
    function ($e) use ($searchedValue) {
        return $e->id == $searchedValue;
    }
);
YurkaTim
источник
16
+1, но array_filterвозвращает массив и не останавливается на первом найденном значении.
Карлос Кампдеррос
4
Это не распознавание $searchedValueвнутри функции. Но снаружи это так.
М. Ахмад Зафар
4
Начнем с того, что этот код не работает так, как $searchedValueвыходит за рамки замыкания. Во-вторых, как вы думаете, эти методы массива работают? Все они зацикливаются внутри массива
Фил
1
Во времена многоядерных процессоров это - к сожалению, в других средах программирования - можно было обрабатывать параллельно, цикл выше не обязательно
FloydThreepwood
3
Для использования $searchedValueнужно написатьfunction ($e) use ($searchedValue) {
Vilintritenmert
20

Использование array_column для переиндексации сэкономит время, если вам нужно будет найти несколько раз:

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

Тогда вы можете просто $lookup[$id]по желанию.

Museful
источник
3
Это был самый удивительный ответ, даже если он не самый интуитивный ...
Тьяго Натанаэль
11
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);
Пабло С.Г. Пачеко
источник
9

Пытаться

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

рабочий пример здесь

Камил Келчевски
источник
1
Очень очень полезно! Спасибо брат!
Фернандо Леон
это не остановится на первом найденном элементе, не так ли?
яугенка
7

Исправив небольшую ошибку @YurkaTim , ваше решение работает для меня, но добавив use:

Использовать $searchedValueвнутри функции одно решение может быть use ($searchedValue)после параметров функции function ($e) HERE.

array_filterфункция возвращает только на , $neededObjectесли условие о возврате являетсяtrue

Если $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): ";
}
yuvilio
источник
1
У вас есть опечатка внутри вашего условия, где вы добавляете результаты. Должно быть так:if ($current_item->someProperty == $needle){ $result_array[] = $current_item; }
Adrum
Скорректированная. Спасибо @adrum!
yuvilio
1

Я сделал это с помощью какой-то таблицы ключей Java. Если вы сделаете это, вам не нужно каждый раз перебирать массив объектов.

<?php

//This is your array with objects
$object1 = (object) array('id'=>123,'name'=>'Henk','age'=>65);
$object2 = (object) array('id'=>273,'name'=>'Koos','age'=>25);
$object3 = (object) array('id'=>685,'name'=>'Bram','age'=>75);
$firstArray = Array($object1,$object2);
var_dump($firstArray);

//create a new array
$secondArray = Array();
//loop over all objects
foreach($firstArray as $value){
    //fill second        key          value
    $secondArray[$value->id] = $value->name;
}

var_dump($secondArray);

echo $secondArray['123'];

вывод:

array (size=2)
  0 => 
    object(stdClass)[1]
      public 'id' => int 123
      public 'name' => string 'Henk' (length=4)
      public 'age' => int 65
  1 => 
    object(stdClass)[2]
      public 'id' => int 273
      public 'name' => string 'Koos' (length=4)
      public 'age' => int 25
array (size=2)
  123 => string 'Henk' (length=4)
  273 => string 'Koos' (length=4)
Henk
Март-Jan
источник
Ах, переиндексация массива по id! Я делаю это обычно, и это делает вещи лучше.
Kzqai
1

Способ мгновенно получить первое значение:

$neededObject = array_reduce(
    $arrayOfObjects,
    function ($result, $item) use ($searchedValue) {
        return $item->id == $searchedValue ? $item : $result;
    }
);
AndreyP
источник
0

Я разместил то, что использую для эффективного решения этой проблемы, здесь, используя быстрый алгоритм двоичного поиска: https://stackoverflow.com/a/52786742/1678210

Я не хотел копировать тот же ответ. Кто-то спросил это немного по-другому, но ответ тот же.

Джастин джек
источник