簡體   English   中英

如何在 PHP 中的多維數組中按 key=>value 進行搜索

[英]How to search by key=>value in a multidimensional array in PHP

有沒有什么快速的方法來獲取在多維數組中找到鍵值對的所有子數組? 我不能說陣列有多深。

簡單示例數組:

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

當我搜索 key=name 和 value="cat 1" 時,該函數應返回:

array(0 => array(id=>1,name=>"cat 1"),
      1 => array(id=>3,name=>"cat 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;
}

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

輸出:

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

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

)

如果效率很重要,您可以編寫它,以便所有遞歸調用將其結果存儲在同一個臨時$results數組中,而不是將數組合並在一起,如下所示:

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

關鍵是search_r通過引用而不是通過值來獲取它的第四個參數; &符號&是至關重要的。

僅供參考:如果您使用的是舊版本的 PHP,那么您必須在對search_r調用中而不是在其聲明中指定傳遞引用部分。 也就是說,最后一行變成search_r($subarray, $key, $value, &$results)

SPL版本怎么樣? 它將為您節省一些輸入:

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

很棒的是,基本上相同的代碼將通過使用 RecursiveDirectoryIterator 而不是 RecursiveArrayIterator 為您遍歷一個目錄。 SPL 是 roxor。

關於 SPL 的唯一遺憾是它在網絡上的記錄很糟糕。 但是有幾本 PHP 書籍介紹了一些有用的細節,尤其是 Pro PHP; 你也可以谷歌搜索更多信息。

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

?>

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

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

對快速版本的小幅改進。

回來為任何需要有關這些答案的優化提示的人發布此更新,尤其是上面約翰·庫格曼 (John Kugelman) 的精彩回答。

他發布的函數工作正常,但我必須優化此場景以處理 12 000 行結果集。 該函數需要一個永恆的 8 秒來遍歷所有記錄,太長了。

我只需要在找到匹配項時停止搜索並返回的功能。 即,如果搜索 customer_id,我們知道結果集中只有一個,一旦我們在多維數組中找到 customer_id,我們就想返回。

這是此功能的速度優化(和大大簡化)版本,適用於任何需要的人。 與其他版本不同的是,它只能處理一個深度的數組,不會遞歸,並且不需要合並多個結果。

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

這降低了將 12 000 條記錄匹配到 1.5 秒的任務。 仍然非常昂貴,但更合理。

小心多維數組中的線性搜索算法(以上是線性的),因為它們的復雜性增加了,因為其深度增加了遍歷整個數組所需的迭代次數。 例如:

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

使用合適的算法最多需要 200 次迭代才能找到您要查找的內容(如果指針位於 [100][1])。

在這種情況下,線性算法以 O(n) 執行(排序整個數組中元素的總數),這很糟糕,一百萬個條目(例如 1000x100x10 數組)平均需要 500,000 次迭代才能找到針。 如果您決定更改多維數組的結構,會發生什么? 如果深度超過 100,PHP 會踢出遞歸算法。計算機科學可以做得更好:

在可能的情況下,始終使用對象而不是多維數組:

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

並應用自定義比較器接口和函數來排序和查找它們:

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

您可以使用uasort()來利用自定義比較器,如果您喜歡冒險,您應該為可以排序和管理它們的對象實現自己的集合(我總是擴展 ArrayObject 以至少包含搜索功能)。

$arrayObj->uasort("myComp");

一旦它們被排序(uasort 是 O(n log n),這與它獲取任意數據一樣好),二分搜索可以在 O(log n) 時間內完成操作,即一百萬個條目只需要約 20 次迭代搜索。 據我所知,自定義比較器二進制搜索未在 PHP 中實現( array_search()使用自然排序,它適用於對象引用而不是它們的屬性),您必須像我一樣自己實現它。

這種方法更有效(不再有深度),更重要的是通用(假設您使用接口強制執行可比性),因為對象定義了它們的排序方式,因此您可以無限地回收代碼。 好多了=)

這是解決方案:

<?php
$students['e1003']['birthplace'] = ("Mandaluyong <br>");
$students['ter1003']['birthplace'] = ("San Juan <br>");
$students['fgg1003']['birthplace'] = ("Quezon City <br>");
$students['bdf1003']['birthplace'] = ("Manila <br>");

$key = array_search('Delata Jona', array_column($students, 'name'));
echo $key;  

?>
$result = array_filter($arr, function ($var) {   
  $found = false;
  array_walk_recursive($var, function ($item, $key) use (&$found) {  
    $found = $found || $key == "name" && $item == "cat 1";
  });
  return $found;
});

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));
function in_multi_array($needle, $key, $haystack) 
{
    $in_multi_array = false;
    if (in_array($needle, $haystack))
    {
        $in_multi_array = true; 
    }else 
    {
       foreach( $haystack as $key1 => $val )
       {
           if(is_array($val)) 
           {
               if($this->in_multi_array($needle, $key, $val)) 
               {
                   $in_multi_array = true;
                   break;
               }
           }
        }
    }

    return $in_multi_array;
} 

我需要類似的東西,但是要按值搜索多維數組...我以約翰為例並寫道

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

我希望它可以幫助某人:)

function findKey($tab, $key){
    foreach($tab as $k => $value){ 
        if($k==$key) return $value; 
        if(is_array($value)){ 
            $find = findKey($value, $key);
            if($find) return $find;
        }
    }
    return null;
}

這是 John K. 發布的一個修改后的函數......我只需要獲取數組中的特定鍵,而不是它上面的任何鍵。

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

如果您知道您的密鑰,我認為最簡單的方法是使用 php 數組函數。

function search_array ( $array, $key, $value )
{
   return array_search($value,array_column($array,$key));
}

這將返回一個索引,您可以通過如下方式找到所需的數據:

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

echo json_encode($arr[search_array($arr,'name','cat 2')]);

此輸出將:

{"id":2,"name":"cat 2"}

另一個版本從找到該值的數組元素返回鍵值(無遞歸,針對速度進行了優化):

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

感謝所有在這里發帖的人。

如果您想搜索鍵數組,這很好

function searchKeysInMultiDimensionalArray($array, $keys)
{
    $results = array();

    if (is_array($array)) {
        $resultArray = array_intersect_key($array, array_flip($keys));
        if (!empty($resultArray)) {
            $results[] = $resultArray;
        }

        foreach ($array as $subarray) {
            $results = array_merge($results, searchKeysInMultiDimensionalArray($subarray, $keys));
        }
    }

    return $results;
}

鍵不會覆蓋,因為每組鍵 => 值將在結果數組中的單獨數組中。
如果您不想要重復的鍵,請使用此鍵

function searchKeysInMultiDimensionalArray($array, $keys)
{
    $results = array();

    if (is_array($array)) {
        $resultArray = array_intersect_key($array, array_flip($keys));
        if (!empty($resultArray)) {
            foreach($resultArray as $key => $single) {

                $results[$key] = $single;
            }
        }

        foreach ($array as $subarray) {
            $results = array_merge($results, searchKeysInMultiDimensionalArray($subarray, $keys));
        }
    }

    return $results;
}

2 個函數: array_search_key_value ,它返回鍵數組以到達具有多維數組中的值的鍵, array_extract_keys返回鍵數組指向的多維數組中的值。

function array_search_key_value($array, $key, $value) {
    if (!is_array($array)) {
        return false;
    }

    return array_search_key_value_aux($array, $key, $value);
}

function array_search_key_value_aux($array, $key, $value, $path=null) {
    if (array_key_exists($key, $array) && $array[$key] === $value) {
        $path[]=$key;

        return $path;
    }

    foreach ($array as $k => $v ) {
        if (is_array($v)) {
            $path[]=$k;

            $p = array_search_key_value_aux($v, $key, $value, $path);

            if ($p !== false) {
                return $p;
            }
        }
    }

    return false;
}

function array_extract_keys($array, $key_list) {
    $v = $array;

    foreach ($key_list as $key) {
        if (!is_array($v) || !array_key_exists($key, $v))
            return false;

        $v = &$v[$key];
    } 
       
    return $v;
}

這是一個單一的測試:

$test_array = array(
    'a' => array(
        'aa' => true,
        'ab' => array(
            'aaa' => array(
                'one' => 1,
                'two' => 2,
                'three' => 3,
                'four' => 4
            ),
            'four' => 4,
            'five' => 5,
        ),
        'six' => 6,
    ),
    'seven' => 7
);

$test_data = array(
    array('one', 1),
    array('two', 2),
    array('three', 3),
    array('four', 4),
    array('five', 5),
    array('six', 6),
    array('seven', 7),
    array('zero', 0),
    array('one', 0),
);

foreach ($test_data as $d) {
    $r = array_search_key_value($test_array, $d[0], $d[1]);

    echo $d[0] . ' => ' . $d[1] . ' ? ', $r ? implode('/', $r) . ' => ' . array_extract_keys($test_array, $r) : 'null', PHP_EOL;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM