PHP - знайти запис власності об'єкта з масиву об'єктів


174

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

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

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

І у мене є ціла змінна назва $v.

Як я можу вибрати запис масиву, у якого є об'єкт, для якого IDвластивість має $vзначення?

Відповіді:


189

Ви або повторюєте масив, шукаючи конкретний запис (нормально одноразовий пошук) або будуєте хешмап за допомогою іншого асоціативного масиву.

Для перших щось подібне

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

Дивіться це питання та наступні відповіді для отримання додаткової інформації щодо останнього - Довідковий масив PHP за кількома індексами


3
встановлення $ item у значення null не потрібно.
dAm2K

32
На жаль, це так :) Тобто, якщо шуканий елемент не знаходиться в масиві. Крім того, ви можете використовувати, isset($item)але я віддаю перевагу належним чином ініціалізувати змінні
Phil

3
Для тих, хто має ключові значення, використовувані для рядківif($v == $struct["ID"]){...
wbadart

67

YurkamTim має рацію. Потрібна лише модифікація:

Після функції ($) вам потрібен вказівник на зовнішню змінну за допомогою "use (& $ searchValue)", і тоді ви можете отримати доступ до зовнішньої змінної. Також ви можете змінити його.

$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 (функція ($ object) {return $ object-> id;}, $ object)); Для PHP 7: array_search ($ object-> id, array_column ($ об’єкти, 'id'));
Майк

3
Це не є кращим відповіді, тому що op запитує масив об'єктів, і вони відповідають лише чистим масивам.
Dwza

8
це неправильно. цей код обробляє масив об'єктів / не плоскі масиви
Тім

31

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

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

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]за бажанням.


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


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

1
У вас є помилка друку в умовному місці, куди ви додаєте тотальну масу результатів. Має бути так:if ($current_item->someProperty == $needle){ $result_array[] = $current_item; }
adrum

Налагоджено. Дякую @adrum!
ювільо

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

Ах, перенастроювання масиву за допомогою id! Я роблю це зазвичай, і це робить речі приємнішими.
Kzqai

1

Спосіб негайно отримати перше значення:

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

0

Я опублікував те, що використовую для ефективного вирішення цієї проблеми тут, використовуючи швидкий алгоритм двійкового пошуку: https://stackoverflow.com/a/52786742/1678210

Я не хотів копіювати ту саму відповідь. Хтось інший запитав це дещо інакше, але відповідь той самий.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.