PHP Çok Boyutlu Dizi Araması (Belirli bir değere göre anahtarı bulun)


115

Bu çok boyutlu diziye sahibim. Aramam ve yalnızca "bilgi" değeriyle eşleşen anahtarı döndürmem gerekiyor. Çok boyutlu dizileri aramakla ilgili başka konular olduğunu biliyorum, ancak durumuma uygulayacak kadar gerçekten anlayamıyorum. Herhangi bir yardım için çok teşekkürler!

Bu yüzden şöyle bir işleve ihtiyacım var:

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

İşte Dizi:

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

Yanıtlar:


157

Çok basit:

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

6
Bu işlevi koşullu bir ifadede kullanıyorsanız, türe karşı mutlak bir kontrol yapmak isteyeceksiniz çünkü döndürülen anahtar bazen [0] dizinine sahip olabilir. Öyleyse, koşullu bir kontrol yapıyorsanız, şunun gibi görünmelidir: if (myfunction($array, 'field', 'value') !== FALSE )) // do something...
Andy Cook

159

Bir başka olası çözüm, array_search()işleve dayanmaktadır . Sen PHP 5.5.0 kullanmak gerekir ya da daha yüksek.

Misal

$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

açıklama

İşlevin array_search()iki bağımsız değişkeni vardır. İlki, aramak istediğiniz değerdir. İkincisi, işlevin arama yapması gereken yerdir. İşlev array_column(), anahtarın olduğu öğelerin değerlerini alır 'uid' .

özet

Yani bunu şu şekilde kullanabilirsiniz:

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

veya tercih ederseniz:

// 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) tarafından orijinal örnek bulunabilir BELGELER . Sayfa .
array_column()


Güncelleme

Vael yorumu nedeniyle merak ediyordum, bu yüzden kullanılan yöntemin performansını ölçmek için basit bir test yaptım. array_search ve kabul edilen yanıtta önerilen .

1000 dizi içeren bir dizi oluşturdum, yapı şöyleydi (tüm veriler rastgele hale getirildi):

[
      {
            "_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"
      },...
]

Ad alanı için farklı değerler arayarak 100 kez arama testini çalıştırdım ve ardından ortalama süreyi milisaniye cinsinden hesapladım . Buraya bir örnek görebilirsiniz.

Sonuçlar, bu cevapta önerilen yöntemin değeri bulmak için 2E-7'ye ihtiyaç duyduğu, kabul edilen cevap yönteminin ise 8E-7'ye ihtiyaç duyduğu şeklindeydi.

Daha önce de söylediğim gibi, bu boyutta bir dizi kullanan bir uygulama için her iki zaman da oldukça kabul edilebilir. Boyut çok büyürse, 1M elemanlar diyelim, o zaman bu küçük fark da artacaktır.

Güncelleme II

array_walk_recursiveBuradaki bazı cevaplarda bahsedilmiş olan yöntem için bir test ekledim . Elde edilen sonuç doğru olanıdır. Ve performansa odaklanırsak, bu testte incelenen diğerlerinden biraz daha kötü . Testte, bunun temel alınan yönteme göre yaklaşık 10 kat daha yavaş olduğunu görebilirsiniz array_search. Yine, bu çoğu uygulama için çok önemli bir fark değildir.

Güncelleme III

Bu yöntemle ilgili çeşitli sınırlamaları tespit ettiği için @ mickmackusa'ya teşekkürler:

  • Bu yöntem ilişkilendirilebilir anahtarlarda başarısız olur.
  • Bu yöntem yalnızca dizinlenmiş alt diziler üzerinde çalışır (0'dan başlayarak ve ardışık olarak artan anahtarlara sahiptir).

Bunun performansını bilen var mı? Nihayetinde daha yavaş olacak gibi görünüyor ve yine de 5.5 gerektirecek. 5.4'te olduğum için test edemiyorum.
Vael Victus

Anlamayanlar için: php 7'de for döngüleri daha hızlıdır. Bu eval.in örneğinde 5.6 olarak değiştirdiğimde, array_search biraz daha hızlıydı.
Vael Victus

zeki! Datumumu bilinen bir anahtarla almak için başka bir dizi yapmak için array_combine () ile array_column () kullanarak benzer bir şey yapıyordum, ama bu daha zarif.
David

4
Alt dizi anahtarları başladığından, array_search()ile kullanmak array_column()OP'nin örnek dizisi üzerinde çalışmayacaktır 1. Bu yöntem aynı zamanda ilişkili anahtarlarda da başarısız olacaktır. Bu yöntem yalnızca dizinlenmiş alt diziler üzerinde çalışır (başlayarak 0ve ardışık olarak artan anahtarlara sahiptir). Bunun nedeni array_column(), döndürülen dizide yeni dizinler üretecek olmasıdır.
mickmackusa

tamamen doğru @ mickmackusa, bilginizi cevaba ekledim. Yardım için teşekkürler
Iván Rodríguez Torres

14

Bu sınıf yöntemi, birden çok koşula göre dizi içinde arama yapabilir:

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

Üretecek:

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

Merhaba Fatalist stackoverflow.com/questions/40860030/… . Bu soruya tekrar cevap veriliyor, lütfen bu soruyu açıklığa kavuşturur
musunuz

4

Bu işlevi kullanın:

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

ve çağrı işlevi.

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

Güzel cevap.
Iván Rodríguez Torres

StackOverflow'da yalnızca kod yanıtları düşük değerlidir. Yaprak düğüm alt dize arama işlevinizin nasıl çalıştığını açıklamak için lütfen yayınınızı güncelleyin. Bu yöntem özellikle OP'nin istediği gibi çalışmak üzere tasarlanmamıştır, bu nedenle farklılıkları açıklığa kavuşturmak önemlidir. Demo bağlantısı, okuyucunun kavrayışını büyük ölçüde artıracaktır. OP'yi ve daha geniş SO kitlesini eğitmek amacıyla her zaman yanıtlar gönderin.
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'da yalnızca kod yanıtları düşük değerlidir. Özyinelemeli yönteminizin nasıl çalıştığını, uygun olduğu durumları ve özyinelemenin gereksiz ek yük olduğu durumları açıklamak için lütfen gönderinizi güncelleyin. OP'yi ve daha geniş SO kitlesini eğitmek amacıyla her zaman yanıtlar gönderin.
mickmackusa

1

Bir sonraki ziyaretçi için: özyinelemeli dizi yürüyüşünü kullanın; çok boyutlu dizideki her "yaprağı" ziyaret eder. İşte ilham için:

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

Sorun değil! sadece size zaman kazandırmak için, josef cevabını denerseniz, işlev tek elemanlı bir dizi döndürür. Anahtar, istenen cevap :)
Iván Rodríguez Torres

@Ivan josef'in cevabı bundan çok farklı. Bunu kendiniz test ettiniz mi? Bu yanıtı gözümün önünde tutuyorum ve işe yarayacağını sanmıyorum çünkü array_walk_recursive bir seviyeyi göremiyor. Her birinci seviye anahtar için josef strpos'u çağırır veya tüm yaprak düğümlerini kontrol eder. Farkı gör?
mickmackusa

Elbette @mickmackusa Ama Hans bir çeşit ilham veriyor, cevap tam anlamıyla çözümü vermiyor. Josef'in cevabında yaptığı gibi, daha fazla ayrıntıya ihtiyacı var. Ancak, bu cevabın sorunu tam olarak çözmediği noktada haklısınız.
Iván Rodríguez Torres

1

$productsSorunun en başında verilen gerçek dizi nerede ?

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

0

Bunu dene

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'da yalnızca kod yanıtları düşük değerlidir. Özyinelemeli yönteminizin nasıl çalıştığını, uygun olduğu durumları ve özyinelemenin gereksiz ek yük olduğu durumları açıklamak için lütfen gönderinizi güncelleyin. OP'yi ve daha geniş SO kitlesini eğitmek amacıyla her zaman yanıtlar gönderin. Ps en php geliştiricileri tercih olacağını düşünüyorum &&ve ||yerine ANDve ORsenin durumunda. Beyan etmek için bir sebep yok current_key. Karşılaştırma $needlekatı olmalıdır.
mickmackusa
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.