PHP çok boyutlu bir dizi anahtar => değer aramak için nasıl

10 Cevap php

Bir anahtar değer çifti çok boyutlu bir dizi bulunan bütün Altdizilim almak için herhangi bir hızlı yolu var mı? Ben dizi olacak kadar derin diyemeyiz.

Basit bir örnek dizisi:

$arr = array(0 => array(id=>1,name=>"cat 1"),
             1 => array(id=>2,name=>"cat 2"),
             2 => array(id=>3,name=>"cat 1")
);

Ben key = adı ve değeri için arama yaptığınızda = "kedi 1" fonksiyonu dönmesi gerekir:

array(0 => array(id=>1,name=>"cat 1"),
      1 => array(id=>3,name=>"cat 1")
);

Ben fonksiyon derin düzeyde aşağı almak için özyinelemeli olması gerekir sanırım.

10 Cevap

Kod:

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

$arr = array(0 => array(id=>1,name=>"cat 1"),
             1 => array(id=>2,name=>"cat 2"),
             2 => array(id=>3,name=>"cat 1"));

print_r(search($arr, 'name', 'cat 1'));

Çıktı:

Array
(
    [0] => Array
        (
            [id] => 1
            [name] => cat 1
        )

    [1] => Array
        (
            [id] => 3
            [name] => cat 1
        )

)

Verimliliği önemli ise bunu tüm yinelemeli çağrılar ziyade birlikte dizileri birleştirilmesi daha aynı geçici $results dizide sonuçlarını saklamak, gibi pek yazabilirim:

function search($array, $key, $value)
{
    $results = array();
    search_r($array, $key, $value, $results);
    return $results;
}

function search_r($array, $key, $value, &$results)
{
    if (!is_array($array)) {
        return;
    }

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

    foreach ($array as $subarray) {
        search_r($subarray, $key, $value, $results);
    }
}

Anahtar var search_r değerine göre referans dördüncü parametre alır ziyade olduğunu; Ampersan & önemlidir.

Bilginize: PHP'nin eski bir sürümü varsa, o zaman daha çok onun bildiriminde daha search_r için call olarak pass-by-reference kısmını belirtmeniz gerekir. Bu son satırı search_r($subarray, $key, $value, &$results) olur, bir.

Nasıl SPL sürümü yerine dersiniz? Size bazı yazarak tasarruf edeceksiniz:

// I changed your input example to make it harder and
// to show it works at lower depths:

$arr = array(0 => array('id'=>1,'name'=>"cat 1"),
             1 => array(array('id'=>3,'name'=>"cat 1")),
             2 => array('id'=>2,'name'=>"cat 2")
);

//here's the code:

    $arrIt = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr));

 foreach ($arrIt as $sub) {
    $subArray = $arrIt->getSubIterator();
    if ($subArray['name'] === 'cat 1') {
        $outputArray[] = iterator_to_array($subArray);
    }
}

Ne harika temelde aynı kod bir RecursiveDirectoryIterator kullanarak yerine RecursiveArrayIterator by, sizin için bir dizin yinelemenize.Ölçütlere olmasıdır. SPL roxor olduğunu.

SPL hakkında tek serseri o kötü web üzerinde belgelenmiş olmasıdır. Ama birkaç PHP kitapların bazı kullanışlı bir detay, özellikle Pro PHP gider; ve muhtemelen de, daha fazla bilgi için google olabilir.

if (isset($array[$key]) && $array[$key] == $value)

Hızlı versiyonu için bir küçük imporvement.

Yukarıdaki John Kugelman harika cevabı kadar özellikle, bu cevaplar üzerine bir optimizasyon ipucu ihtiyaç duyan herkes için bu güncelleme sonrası geri geldi.

Onun işlevi çalışma cezası yayınlanmıştır ama ben bir 12 000 satır resultset işlemek için bu senaryoyu optimize zorunda kaldı. Işlevi waaaaaay çok uzun, tüm kayıtlarda geçmesi için sonsuz bir 8 saniye alıyordu.

I simply needed the function to STOP searching and return when match was found. Ie, if searching for a customer_id, we know we only have one in the resultset and once we find the customer_id in the multidimensional array, we want to return.

Burada hız optimize edilmiş (ve çok daha basitleştirilmiş) Bu fonksiyonun sürümü ihtiyacı olan herkes için vardır. Diğer sürümünden farklı olarak, sadece dizinin sadece bir derinliği, özyineleme değil işleyebilir ve birden çok sonuç birleştirilmesi ile ortadan kaldırıyor.

// search array for specific key = value
public function searchSubArray(Array $array, $key, $value) {   
    foreach ($array as $subarray){  
        if (isset($subarray[$key]) && $subarray[$key] == $value)
          return $subarray;       
    } 
}

Bu bir 1,5 saniye için 12 000 kayıtları eşleşecek görevi aşağı getirdi. Still very costly ama çok daha makul.

Derinliği tüm dizi hareket için gerekli yineleme sayısını artırır onlar karmaşıklığı bileşik gibi, çok boyutlu diziler doğrusal arama algoritmaları (yukarıdaki doğrusal) dikkatli olun. Örn:

array(
    [0] => array ([0] => something, [1] => something_else))
    ...
    [100] => array ([0] => something100, [1] => something_else100))
)

uygun bir algoritma ile, (iğne [100] [1] at olsaydı) sizin için ne arıyorsanız bulmak için en fazla 200 tekrarlamalar da alacaktı.

Bu durumda doğrusal algoritmalar bir milyon girdileri (örneğin 1000x100x10 dizi) iğneyi bulmak için ortalama 500.000 yineleme alacağını, bu kötüdür, O (n) de (tüm dizideki elemanların sipariş sayısını) gerçekleştirin. Eğer çok boyutlu dizinin yapısını değiştirmeye karar verirseniz de ne olurdu? . Derinlik 100'den fazla Bilgisayar bilimi daha iyi yapabilirim Ve eğer PHP bir özyinelemeli algoritma tekmeyi olacaktır:

Mümkünse, her zaman yerine, çok boyutlu diziler nesneleri kullanabilirsiniz:

ArrayObject(
   MyObject(something, something_else))
   ...
   MyObject(something100, something_else100))
)

ve bunları sıralamak ve bulmak için özel bir karşılaştırma arayüzü ve işlevi uygulamak:

interface Comparable {
   public function compareTo(Comparable $o);
}

class MyObject implements Comparable {
   public function compareTo(Comparable $o){
      ...
   }
}

function myComp(Comparable $a, Comparable $b){
    return $a->compareTo($b);
}

(Ben her zaman çok bir arama fonksiyonu dahil ArrayObject genişletmek maceracı hissettiğiniz sıralamak ve bunları yönetebilirsiniz nesneler için kendi koleksiyonları uygulamak gerektiğini, uasort() özel bir karşılaştırıcı kullanmak için kullanabileceğiniz az).

$arrayObj->uasort("myComp");

Onlar sıralanır kez (uasort (n keyfi veriler üzerinde alır kadar iyi olduğu,) log n, O), ikili arama O'da işlemi yapabilirsiniz (log n) zaman, yani bir milyon girişleri yalnızca ~ 20 yineleme alır arama. Bildiğim kadarıyla benim gibi farkında özel karşılaştırma ikili arama (array_search() nesne referanslarıyla değil, kendi özellikleri çalışır doğal sıralamayı kullanır) PHP uygulanan değil, sen benim yaptığım gibi bu kendini uygulamak gerekir.

Bu yaklaşım daha verimli (bir derinlik artık yoktur) ve nesneler onlar sıralanır nasıl tanımlamak, böylece sonsuz kodunu geri çünkü daha da önemlisi evrensel (Eğer arayüzleri kullanarak karşılaştırılabilir zorlamak varsayarak). Çok daha iyi =)

Basit ve temiz bu çözümü deneyin:

<?php
$arr = array(0 => array("id"=>1,"name"=>"cat 1"),
             1 => array("id"=>2,"name"=>"cat 2"),
             2 => array("id"=>3,"name"=>"cat 1")
);
$arr = array_filter($arr, function($ar) {
   return ($ar['name'] == 'cat 1');
   //return ($ar['name'] == 'cat 1' AND $ar['id'] == '3');// you can add multiple conditions
});

echo "<pre>";
print_r($arr);

?>

Ref: http://php.net/manual/en/function.array-filter.php

Ve değer (hız için optimize edilmiş Yinelemesiz) bulunmus dizi öğeden anahtar değerini döndürür başka bir versiyonu:

// if the array is 
$arr['apples'] = array('id' => 1);
$arr['oranges'] = array('id' => 2);

//then 
print_r(search_array($arr, 'id', 2);
// returns Array ( [oranges] => Array ( [id] => 2 ) ) 
// instead of Array ( [0] => Array ( [id] => 2 ) )

// search array for specific key = value
function search_array($array, $key, $value) {
  $return = array();   
  foreach ($array as $k=>$subarray){  
    if (isset($subarray[$key]) && $subarray[$key] == $value) {
      $return[$k] = $subarray;
      return $return;
    } 
  }
}

Burada yayınlanan herkese teşekkürler.

Benzer bir şey gerekli, ama değeri çok boyutlu dizi aramak için ... Ben John örnek aldı ve yazdı

function _search_array_by_value($array, $value) {
        $results = array();
        if (is_array($array)) {
            $found = array_search($value,$array);
            if ($found) {
                $results[] = $found;
            }
            foreach ($array as $subarray)
                $results = array_merge($results, $this->_search_array_by_value($subarray, $value));
        }
        return $results;
    }

Ben Birini yardımcı olur umarım :)

http://snipplr.com/view/51108/nested-array-search-by-value-or-key/

<?php

//PHP 5.3

function searchNestedArray(array $array, $search, $mode = 'value') {

    foreach (new RecursiveIteratorIterator(new RecursiveArrayIterator($array)) as $key => $value) {
        if ($search === ${${"mode"}})
            return true;
    }
    return false;
}

$data = array(
    array('abc', 'ddd'),
    'ccc',
    'bbb',
    array('aaa', array('yyy', 'mp' => 555))
);

var_dump(searchNestedArray($data, 555));

Bu John K. gönderdi ... Ben yukarıda dizisi ve hiçbir şey, sadece belirli anahtar kapmak için gereken birinden bir revize fonksiyonudur.

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

    if ( is_array($array) )
    {
        if ( $array[$key] == $value )
        {
            $results[] = $array;
        } else {
            foreach ($array as $subarray) 
                $results = array_merge( $results, $this->search_array($subarray, $key, $value) );
        }
    }

    return $results;
}

$arr = array(0 => array(id=>1,name=>"cat 1"),
       1 => array(id=>2,name=>"cat 2"),
       2 => array(id=>3,name=>"cat 1"));

print_r(search_array($arr, 'name', 'cat 1'));