PHP Multidimensional Array Searching (ค้นหาคีย์ตามค่าเฉพาะ)


115

ฉันมีอาร์เรย์หลายมิตินี้ ฉันต้องการค้นหาและส่งคืนเฉพาะคีย์ที่ตรงกับค่าของ "กระสุน" ฉันรู้ว่ามีหัวข้ออื่น ๆ เกี่ยวกับการค้นหาอาร์เรย์หลายมิติ แต่ฉันไม่เข้าใจมากพอที่จะนำไปใช้กับสถานการณ์ของฉัน ขอบคุณมากสำหรับความช่วยเหลือ!

ดังนั้นฉันต้องการฟังก์ชั่นเช่น:

myfunction($products,'breville-one-touch-tea-maker-BTM800XL');
// returns 1

นี่คือ Array:

$products = array (
1  => array(
        'name'          => 'The Breville One-Touch Tea Maker',
        'slug'          => 'breville-one-touch-tea-maker-BTM800XL',
        'shortname'     => 'The One-Touch Tea Maker',
        'listprice'     => '299.99',
        'price'         => '249.99',
        'rating'        => '9.5',
        'reviews'       => '81',
        'buyurl'        => 'http://www.amazon.com/The-Breville-One-Touch-Tea-Maker/dp/B003LNOPSG',
        'videoref1'     => 'xNb-FOTJY1c',
        'videoref2'     => 'WAyk-O2B6F8',
        'image'         => '812BpgHhjBML.jpg',
        'related1'      => '2',
        'related2'      => '3',
        'related3'      => '4',
        'bestbuy'       => '1',
        'quote'         => '',
        'quoteautor'    => 'K. Martino',
        ),

2  => array(
        'name'          => 'Breville Variable-Temperature Kettle BKE820XL',
        'slug'          => 'breville-variable-temperature-kettle-BKE820XL',
        'shortname'     => 'Variable Temperature Kettle',
        'listprice'     => '199.99',
        'price'         => '129.99',
        'rating'        => '9',
        'reviews'       => '78',
        'buyurl'        => 'http://www.amazon.com/Breville-BKE820XL-Variable-Temperature-1-8-Liter-Kettle/dp/B001DYERBK',
        'videoref1'     => 'oyZWBD83xeE',
        'image'         => '41y2B8jSKmwL.jpg',
        'related1'      => '3',
        'related2'      => '4',
        'related3'      => '5',
        'bestbuy'       => '1',
        'quote'         => '',
        'quoteautor'    => '',
        ),
);

คำตอบ:


157

ง่ายมาก:

function myfunction($products, $field, $value)
{
   foreach($products as $key => $product)
   {
      if ( $product[$field] === $value )
         return $key;
   }
   return false;
}

6
หากคุณกำลังใช้ฟังก์ชันนี้ในคำสั่งเงื่อนไขคุณจะต้องทำการตรวจสอบแบบสัมบูรณ์กับประเภทเนื่องจากบางครั้งคีย์ที่ส่งคืนอาจมีดัชนีเป็น [0] ดังนั้นหากทำการตรวจสอบเงื่อนไขควรมีลักษณะดังนี้: if (myfunction($array, 'field', 'value') !== FALSE )) // do something...
Andy Cook

159

อีกวิธีหนึ่งที่เป็นไปได้นั้นขึ้นอยู่กับarray_search()ฟังก์ชัน คุณต้องใช้ PHP 5.5.0ขึ้นไป

ตัวอย่าง

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

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

echo ("The key is: ".$key);
//This will output- The key is: 2

คำอธิบาย

ฟังก์ชันarray_search()มีสองอาร์กิวเมนต์ ค่าแรกคือค่าที่คุณต้องการค้นหา ประการที่สองคือตำแหน่งที่ควรค้นหาฟังก์ชัน ฟังก์ชั่นได้รับค่าขององค์ประกอบที่สำคัญคือarray_column() 'uid'

สรุป

ดังนั้นคุณสามารถใช้เป็น:

array_search('breville-one-touch-tea-maker-BTM800XL', array_column($products, 'slug'));

หรือหากคุณต้องการ:

// define function
function array_search_multidim($array, $column, $key){
    return (array_search($key, array_column($array, $column)));
}

// use it
array_search_multidim($products, 'slug', 'breville-one-touch-tea-maker-BTM800XL');

ตัวอย่างเดิม (โดย xfoxawy) สามารถพบได้บนเอกสาร หน้า
array_column()


ปรับปรุง

เนื่องจากความคิดเห็นของ Vael ฉันอยากรู้ดังนั้นฉันจึงทำการทดสอบง่ายๆเพื่อให้มั่นใจถึงประสิทธิภาพของวิธีการที่ใช้array_searchและวิธีการที่เสนอในคำตอบที่ยอมรับ

ฉันสร้างอาร์เรย์ที่มีอาร์เรย์ 1,000 อาร์เรย์โครงสร้างเป็นแบบนี้ (ข้อมูลทั้งหมดเป็นแบบสุ่ม):

[
      {
            "_id": "57fe684fb22a07039b3f196c",
            "index": 0,
            "guid": "98dd3515-3f1e-4b89-8bb9-103b0d67e613",
            "isActive": true,
            "balance": "$2,372.04",
            "picture": "http://placehold.it/32x32",
            "age": 21,
            "eyeColor": "blue",
            "name": "Green",
            "company": "MIXERS"
      },...
]

ฉันวิ่งทดสอบการค้นหา 100 ครั้งค้นหาค่าที่แตกต่างกันสำหรับเขตข้อมูลชื่อและแล้วผมคำนวณเวลาเฉลี่ยในมิลลิวินาที ที่นี่คุณสามารถดูตัวอย่าง

ผลลัพธ์คือวิธีการที่เสนอในคำตอบนี้ต้องการประมาณ 2E-7 ในการหาค่าในขณะที่วิธีการตอบที่ยอมรับนั้นต้องการประมาณ 8E-7

อย่างที่ฉันได้กล่าวไปแล้วทั้งสองครั้งนั้นค่อนข้างยอมรับได้สำหรับแอปพลิเคชันที่ใช้อาร์เรย์ที่มีขนาดเท่านี้ ถ้าขนาดใหญ่ขึ้นมากสมมติว่าองค์ประกอบ 1M ความแตกต่างเล็กน้อยนี้ก็จะเพิ่มขึ้นด้วย

อัปเดต II

ฉันได้เพิ่มการทดสอบสำหรับวิธีการตามarray_walk_recursiveที่กล่าวถึงแล้วสำหรับคำตอบบางส่วนที่นี่ ผลลัพธ์ที่ได้คือผลลัพธ์ที่ถูกต้อง และถ้าเรามุ่งเน้นไปที่ประสิทธิภาพมันจะแย่กว่าที่คนอื่นตรวจสอบในการทดสอบเล็กน้อย ในการทดสอบคุณจะเห็นว่าเป็นเรื่องเกี่ยวกับ 10 array_searchครั้งช้ากว่าวิธีการที่อยู่บนพื้นฐานของ อีกครั้งนี่ไม่ใช่ความแตกต่างที่เกี่ยวข้องกับแอปพลิเคชันส่วนใหญ่

อัปเดต III

ขอบคุณ @mickmackusa ที่ระบุข้อ จำกัด หลายประการเกี่ยวกับวิธีนี้:

  • วิธีนี้จะล้มเหลวในคีย์การเชื่อมโยง
  • วิธีนี้จะใช้ได้เฉพาะกับ subarrays ที่จัดทำดัชนีเท่านั้น (เริ่มจาก 0 และมีคีย์จากน้อยไปหามาก)

ไม่มีใครรู้ประสิทธิภาพของตัวนี้? ดูเหมือนว่าท้ายที่สุดแล้วมันจะช้าลงและยังต้องใช้ 5.5 ฉันไม่สามารถทดสอบได้เนื่องจากฉันใช้ 5.4
Vael Victus

สำหรับใครที่ไม่เข้าใจ: ใน php 7 นั้น for loops นั้นเร็วกว่า เมื่อฉันเปลี่ยนเป็น 5.6 ในตัวอย่าง eval.in นั้น array_search เร็วขึ้นเล็กน้อย
Vael Victus

ฉลาด! ฉันกำลังทำอะไรบางอย่างที่คล้ายกันโดยใช้ array_combine () กับ array_column () เพื่อสร้างอาร์เรย์อื่นที่จะดึงข้อมูลของฉันด้วยคีย์ที่รู้จัก แต่มันดูหรูหรากว่า
เดวิด

4
ใช้array_search()กับarray_column()จะไม่ทำงานบนอาร์เรย์ตัวอย่าง OP เพราะปุ่ม subarray 1เริ่มต้นจาก วิธีนี้จะล้มเหลวในคีย์การเชื่อมโยง วิธีนี้จะใช้ได้เฉพาะกับ subarrays ที่จัดทำดัชนีเท่านั้น (เริ่มจาก0และมีคีย์จากน้อยไปหามาก) สาเหตุนี้เป็นเพราะarray_column()จะสร้างดัชนีใหม่ในอาร์เรย์ที่ส่งคืน
mickmackusa

ถูกต้อง @mickmackusa ฉันได้เพิ่มความรู้ของคุณในคำตอบ ขอบคุณสำหรับความช่วยเหลือ
IvánRodríguez Torres

14

เมธอดคลาสนี้สามารถค้นหาในอาร์เรย์ได้หลายเงื่อนไข:

class Stdlib_Array
{
    public static function multiSearch(array $array, array $pairs)
    {
        $found = array();
        foreach ($array as $aKey => $aVal) {
            $coincidences = 0;
            foreach ($pairs as $pKey => $pVal) {
                if (array_key_exists($pKey, $aVal) && $aVal[$pKey] == $pVal) {
                    $coincidences++;
                }
            }
            if ($coincidences == count($pairs)) {
                $found[$aKey] = $aVal;
            }
        }

        return $found;
    }    
}

// Example:

$data = array(
    array('foo' => 'test4', 'bar' => 'baz'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test1', 'bar' => 'baz3'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test',  'bar' => 'baz4'),
    array('foo' => 'test4', 'bar' => 'baz1'),
    array('foo' => 'test',  'bar' => 'baz1'),
    array('foo' => 'test3', 'bar' => 'baz2'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test4', 'bar' => 'baz1')
);

$result = Stdlib_Array::multiSearch($data, array('foo' => 'test4', 'bar' => 'baz1'));

var_dump($result);

จะผลิต:

array(2) {
  [5]=>
  array(2) {
    ["foo"]=>
    string(5) "test4"
    ["bar"]=>
    string(4) "baz1"
  }
  [10]=>
  array(2) {
    ["foo"]=>
    string(5) "test4"
    ["bar"]=>
    string(4) "baz1"
  }
}

หวัดดี Fatalist stackoverflow.com/questions/40860030/… . คำถามเหล่านี้ถูกย้อนกลับไปอีกครั้งคุณช่วยชี้แจงคำถามนั้นได้
ไหม

4

ใช้ฟังก์ชันนี้:

function searchThroughArray($search,array $lists){
        try{
            foreach ($lists as $key => $value) {
                if(is_array($value)){
                    array_walk_recursive($value, function($v, $k) use($search ,$key,$value,&$val){
                        if(strpos($v, $search) !== false )  $val[$key]=$value;
                    });
            }else{
                    if(strpos($value, $search) !== false )  $val[$key]=$value;
                }

            }
            return $val;

        }catch (Exception $e) {
            return false;
        }
    }

และฟังก์ชั่นการโทร

print_r(searchThroughArray('breville-one-touch-tea-maker-BTM800XL',$products));

คำตอบที่ดี คุณสามารถตรวจสอบประสิทธิภาพของข้อเสนอของคุณได้จากคำตอบของฉัน
IvánRodríguez Torres

คำตอบรหัสเท่านั้นมีค่าต่ำใน StackOverflow โปรดอัปเดตโพสต์ของคุณเพื่ออธิบายว่าฟังก์ชันการค้นหาสตริงย่อยของโหนดลีฟทำงานอย่างไร วิธีนี้ไม่ได้ออกแบบมาโดยเฉพาะให้ทำงานตามที่ OP ขอดังนั้นจึงเป็นเรื่องสำคัญที่จะต้องชี้แจงความแตกต่าง ลิงก์สาธิตจะช่วยเพิ่มความเข้าใจของผู้อ่านได้มาก โพสต์คำตอบโดยมีจุดประสงค์เพื่อให้ความรู้แก่ OP และผู้ชม SO ที่มากขึ้นเสมอ
mickmackusa

1
function search($array, $key, $value) 
{ 
    $results = array(); 

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

        foreach ($array as $subarray) 
            $results = array_merge($results, search($subarray, $key, $value)); 
    } 

    return $results; 
} 

คำตอบรหัสเท่านั้นมีค่าต่ำใน StackOverflow โปรดอัปเดตโพสต์ของคุณเพื่ออธิบายวิธีการทำงานซ้ำของคุณสถานการณ์ที่เหมาะสมและสถานการณ์ที่การเรียกซ้ำเป็นค่าใช้จ่ายที่ไม่จำเป็น โพสต์คำตอบโดยมีจุดประสงค์เพื่อให้ความรู้แก่ OP และผู้ชม SO ที่มากขึ้นเสมอ
mickmackusa

1

สำหรับผู้เยี่ยมชมคนต่อไป: ใช้การเดินอาร์เรย์แบบเรียกซ้ำ; มันเข้าชมทุก "ใบไม้" ในอาร์เรย์หลายมิติ นี่คือแรงบันดาลใจ:

function getMDArrayValueByKey($a, $k) {
    $r = [];
    array_walk_recursive ($a, 
                          function ($item, $key) use ($k, &$r) {if ($key == $k) $r[] = $item;}
                          );
    return $r;
}

ไม่มีปัญหา! เพียงเพื่อช่วยคุณประหยัดเวลาหากคุณลองใช้คำตอบของ josef ฟังก์ชันจะส่งคืนอาร์เรย์พร้อมองค์ประกอบเดียว กุญแจสำคัญคือคำตอบที่ต้องการ :)
IvánRodríguez Torres

คำตอบของ @Ivan josef แตกต่างจากข้อนี้มาก คุณทดสอบด้วยตัวเองหรือไม่ ฉันจับตาดูคำตอบนี้อยู่เสมอและไม่คิดว่าจะได้ผลเพราะ array_walk_recursive ไม่สามารถมองเห็นระดับได้ สำหรับคีย์ระดับแรกแต่ละอัน josef จะเรียกใช้ strpos หรือตรวจสอบ leafnodes ทั้งหมด ดูความแตกต่าง?
mickmackusa

แน่นอน @mickmackusa แต่ Hans กำลังให้แรงบันดาลใจบางอย่างคำตอบคือไม่ได้ให้คำตอบอย่างแท้จริง มันต้องการรายละเอียดเพิ่มเติมเช่นเดียวกับที่ Josef ตอบกับคำตอบของเขา แต่คุณคิดถูกแล้วที่คำตอบนี้ไม่สามารถแก้ปัญหาได้อย่างสมบูรณ์
IvánRodríguez Torres

1

ฉันต้องการด้านล่าง$productsอาร์เรย์จริงที่ระบุในปัญหาตอนเริ่มต้นอยู่ที่ไหน

print_r(
  array_search("breville-variable-temperature-kettle-BKE820XL", 
  array_map(function($product){return $product["slug"];},$products))
);

0

ลองทำตามนี้

function recursive_array_search($needle,$haystack) {
        foreach($haystack as $key=>$value) {
            $current_key=$key;
            if($needle==$value['uid'] OR (is_array($value) && recursive_array_search($needle,$value) !== false)) {
                return $current_key;
            }
        }
        return false;
    }

คำตอบรหัสเท่านั้นมีค่าต่ำใน StackOverflow โปรดอัปเดตโพสต์ของคุณเพื่ออธิบายวิธีการทำงานซ้ำของคุณสถานการณ์ที่เหมาะสมและสถานการณ์ที่การเรียกซ้ำเป็นค่าใช้จ่ายที่ไม่จำเป็น โพสต์คำตอบโดยมีจุดประสงค์เพื่อให้ความรู้แก่ OP และผู้ชม SO ที่มากขึ้นเสมอ Ps ฉันคิดว่านักพัฒนา php ส่วนใหญ่จะชอบ&&และ||แทนที่จะเป็นANDและORอยู่ในสภาพของคุณ current_keyไม่มีเหตุผลที่จะไม่ประกาศ การเปรียบเทียบ$needleควรเข้มงวด
mickmackusa
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.