2011-03-25 47 views
1

這是一種常見的實現問題。如果我有一個任意深度的數組,並且事先不知道密鑰是什麼,那麼訪問關聯數組的特定路徑上的值的最佳方法是什麼?例如,假設數組:從關聯數組中獲取嵌套值

array(
    'great-grandparent' = array(
     'grandparent' = array(
      'parent' = array(
        'child' = 'value'; 
      ), 
       'parent2' = 'value'; 
     ), 
     'grandparent2' = 'value'; 
    ) 
); 

請告訴我在$array['great-grandparent']['grandparent']['parent']['child']牢記,我不知道該組鍵來訪問值的最佳方式。我已經使用eval將上面的語法構造爲具有變量名稱的字符串,然後評估字符串以獲取數據。但eval是緩慢的,我希望更快的事情。喜歡的東西$class->getConfigValue('great-grandparent/grandparent/'.$parent.'/child');,將返回「價值」

評估和演示代碼示例

public function getValue($path, $withAttributes=false) { 
     $path = explode('/', $path); 
     $rs = '$r = $this->_data[\'config\']'; 
     foreach ($path as $attr) { 
      $rs .= '[\'' . $attr . '\']'; 
     } 
     $rs .= ';'; 
     $r = null; 
     @eval($rs); 
     if($withAttributes === false) { 
      $r = $this->_removeAttributes($r); 
     } 
     return $r; 
    } 
+0

您是evaling?你能向我們展示一個例子嗎? – 2011-03-25 21:43:51

+0

添加了評估代碼。它基本上採用/定界的路徑,並將其轉換爲數組訪問語法,然後進行評估。 – chris 2011-03-25 21:50:01

+0

你正在用這個實現一個配置系統嗎? – 2011-03-25 21:50:28

回答

2

我不知道潛在的速度,但你不不需要使用eval來做這樣的搜索:

$conf = array(
     'great-grandparent' => array(
      'grandparent' => array(
       'parent' => array(
        'child' => 'value searched' 
       ), 
       'parent2' => 'value' 
      ), 
      'grandparent2' => 'value' 
    ) 
); 

    $path = 'great-grandparent/grandparent/parent/child'; 
    $path = explode('/', $path); 

    $result = $conf; 

    while(count($path) > 0) { 
     $part = array_shift($path); 

     if (is_array($result) && array_key_exists($part, $result)) { 
      $result = $result[$part]; 
     } else { 
      $result = null; 
      break; 
     } 
    } 

    echo $result; 
+0

+1一直在工作我自己的算法:)你的解決方案不工作100%正確我認爲,嘗試一個像這樣的路徑'grand-grandparent/grandparent2/parent2'我得到'v'作爲輸出應該是不正確的。 – 2011-03-25 22:31:48

+0

@Nick Weaver:哦,我沒有管理我的示例中的錯誤案例,現在添加它。 – 2011-03-25 22:45:41

0

在這裏,我們走了,我的解決方案:

$tree = array(
    'great-grandparent' => array(
     'grandparent' => array(
      'parent' => array(
        'child' => 'value1' 
      ), 
       'parent2' => 'value2' 
     ), 
     'grandparent2' => 'value3' 
    ) 
); 

$pathParts = explode('/','great-grandparent/grandparent/parent/child'); 
$pathParts = array_reverse($pathParts); 

echo retrieveValueForPath($tree, $pathParts); 

function retrieveValueForPath($node, $pathParts) { 
    foreach($node as $key => $value) { 
     if(($key == $pathParts[count($pathParts)-1]) && (count($pathParts)==1)) { 
      return $value; 
     }  

     if($key == $pathParts[count($pathParts)-1]) { 
      array_pop($pathParts); 
     } 

     if(is_array($value)) { 
      $result = retrieveValueForPath($value, $pathParts); 
     } 
    } 

    return $result; 
} 
+0

我有一個xml實現,但xml解析速度太慢,我以爲這裏有人可能有一個簡單的解決方案,我忽略了。 xml的問題是合併節點和節點繼承時涉及到的複雜性 – chris 2011-03-25 21:54:43

+1

parse_ini返回一個我已經創建的數組,因此不需要從ini文件獲取數組 – chris 2011-03-25 21:59:50

+0

好的,在這裏我們將使用遞歸。 – 2011-03-25 22:40:41