PHP - ค้นหารายการตามคุณสมบัติของวัตถุจากอาร์เรย์ของวัตถุ


174

อาร์เรย์ดูเหมือนว่า:

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

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

$vและฉันมีตัวแปรจำนวนเต็มที่เรียกว่า

ฉันจะเลือกรายการอาร์เรย์ที่มีวัตถุที่IDทรัพย์สินมี$vค่าได้อย่างไร

คำตอบ:


189

คุณทำซ้ำอาร์เรย์ค้นหาระเบียนเฉพาะ (ตกลงในการค้นหาเพียงครั้งเดียวเท่านั้น) หรือสร้าง hashmap โดยใช้อาร์เรย์เชื่อมโยงอื่น

สำหรับอดีตสิ่งเช่นนี้

$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 (& $ SearchesValue)" จากนั้นคุณสามารถเข้าถึงตัวแปรภายนอกได้ นอกจากนี้คุณสามารถแก้ไขได้

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

2
คุณถูกต้องเกี่ยวกับการดัดแปลงและมันก็เป็นวิธีที่เรียบร้อย แต่ฉันทดสอบความเร็วเทียบกับการวนซ้ำผ่านวัตถุ - ตัวคุณเองเพราะอย่างที่ @phil ชี้ให้เห็น array_filter กำลังทำสิ่งนี้เช่นกัน - และวิธีนี้ใช้เวลาประมาณห้า ครั้งอีกต่อไป วัตถุทดสอบของฉันไม่ใช่วัตถุขนาดใหญ่ดังนั้นจึงอาจแย่ลงไปอีก
Nicolai

9
&ไม่จำเป็นต้องใช้เมื่อนำเข้า$searchedValueลงในขอบเขตปิด &ใช้ในการสร้างการอ้างอิงที่จำเป็นเท่านั้นหาก$searchedValueได้รับการแก้ไขภายในปิด
Stefan Gehrig

มันเท่ห์มาก ฉันไม่รู้ว่า PHP สามารถทำสิ่งนี้ได้ ฉันคิดว่าการใช้globalเป็นเพียงการแบ่งปันข้อมูลในฟังก์ชั่น! แต่มันก็น่าเสียดายถ้านี่ช้าจริงๆ :(
NoOne

13
TS ขอรายการเดียวรหัสนี้ส่งกลับอาร์เรย์
Pavel Vlasov

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;}, $ objects)); สำหรับ PHP 7: array_search ($ object-> id, array_column ($ objects, 'id'));
Mike

3
นี่ไม่ใช่คำตอบที่ต้องการเนื่องจาก op ขอให้อาร์เรย์ของวัตถุและคำตอบนี้จัดการกับอาร์เรย์ที่บริสุทธิ์เท่านั้น
Dwza

8
นั่นไม่ถูกต้อง รหัสนี้จะจัดการกับอาร์เรย์ของวัตถุ / อาร์เรย์ที่ไม่ใช่แบบแบน
ทิม

31

ฉันได้พบทางออกที่สง่างามมากขึ้นที่นี่ ปรับให้เข้ากับคำถามที่อาจมีลักษณะ:

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

16
+1 แต่array_filterส่งคืนอาร์เรย์และจะไม่หยุดที่ค่าแรกที่พบ
Carlos Campderrós

4
ไม่รู้จัก$searchedValueภายในฟังก์ชั่น แต่ข้างนอกนั้น
M. Ahmad Zafar

4
สำหรับผู้เริ่มรหัสนี้ใช้ไม่ได้เนื่องจาก$searchedValueอยู่นอกขอบเขตการปิด ประการที่สองคุณคิดว่าวิธีการเรียงลำดับเหล่านี้ทำงานอย่างไร พวกเขาวนรอบอาร์เรย์ภายใน
Phil

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
นี่เป็นคำตอบที่น่าอัศจรรย์ที่สุดแม้ว่าจะไม่ใช่คำหยั่งรู้ที่สุด ...
Thiago Natanael

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
มีประโยชน์มากมาก! ขอบคุณมาก!
Fernando León

มันจะไม่หยุดอยู่ที่องค์ประกอบแรกที่พบมันจะได้หรือไม่
yaugenka

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

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
คุณพิมพ์ผิดภายในเงื่อนไขที่คุณเพิ่มจำนวนเขาผลลัพธ์ _array ควรเป็นเช่นนี้:if ($current_item->someProperty == $needle){ $result_array[] = $current_item; }
adrum

ปรับ ขอบคุณ @adrum!
yuvilio

1

ฉันทำสิ่งนี้โดยใช้ Java keymap บางประเภท หากคุณทำเช่นนั้นคุณไม่จำเป็นต้องวนซ้ำวัตถุของคุณทุกครั้ง

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

ฉันไม่ต้องการคัดลอกคำตอบเดียวกัน มีคนอื่นถามมันแตกต่างกันเล็กน้อย แต่คำตอบก็เหมือนกัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.