2010-06-15 16 views
2

PHP中有可能使用特定鍵路徑從數組中提取值並返回這些值的數組?我將用一個例子解釋:從PHP中使用一個特定鍵提取數組中的值的泛型函數PHP

$user = 
    array (
    array(
     'id' => 1, 
     'email' =>'[email protected]', 
     'project' => array ('project_id' => 222, 'project_name' => 'design') 
    ), 
    array(
     'id' => 2, 
     'email' =>'[email protected]', 
     'project' => array ('project_id' => 333, 'project_name' => 'design') 
    ) 
); 

/** I have to write a function something like: */ 
$projectIds = extractValuesWithKey($user, array('project', 'project_id')); 
print_r($projectIds); 

輸出:

Array(
[0] => 222, 
[1] => 333 
) 
+0

是具有關鍵路徑強制性的,如你是否必須擁有項目下的所有project_id或是否獲得所有project_id鍵(不管它們在數組中的位置)是否足夠?而且,這是一個固定的陣列結構,例如它會一直有$ user [n] ['project'] ['project_id']? – Gordon 2010-06-15 10:53:52

+0

是的。我想使它通用。 陣列結構可以不同。說再次包含「成員陣列」的「一系列項目」。 – Sabya 2010-06-15 10:58:24

+0

關於你的第二個問題,是的,如果可能的話。那麼有可能將「id」作爲關鍵字。其中可能是project_id或user_id。 – Sabya 2010-06-15 11:03:08

回答

1

好,比你認爲的更容易。

function extractValuesWithKey($array, $parts) { 
    $return = array(); 
    $rawParts = $parts; 
    foreach ($array as $value) { 
     $tmp = $value; 
     $found = true; 
     foreach ($parts as $key) { 
      if (!is_array($tmp) || !isset($tmp[$key])) { 
       $found = false; 
       continue; 
      } else { 
       $tmp = $tmp[$key]; 
      } 
     } 
     if ($found) { 
      $return[] = $tmp; 
     } 
    } 
    return $return; 
} 
1

如果 '關鍵路徑' 是不是動態的,你可以做一個班輪與array_map

$projectIds = array_map(function($arr) { return $arr['project']['project_id']; }, $user); 

另外,動態路徑:

function extractValuesWithKey($users, $path) { 
return array_map(function($array) use ($path) { 
    array_walk($path, function($key) use (&$array) { $array = $array[$key]; }); 
    return $array; 
}, $users); 
} 

的封鎖/匿名函數只適用於PHP 5.3+,我不知道這將如何比較性能明智的雙foreach循環。還要注意,沒有錯誤檢查來確保路徑存在。

+0

+1。接受雙foreach循環,因爲它也運行在PHP 5.2上。 – Sabya 2010-06-15 12:07:52

2

我早就走了不同的方法(不是說有什麼錯誤與陣列功能爲主的答案),通過使用遞歸迭代壓扁這使得關鍵路徑比較相當簡單的陣列。

function extractValuesWithKey($array, $keys) { 
    $iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($array)); 
    $keys_count = count($keys); 
    // No point going deeper than we have to! 
    $iterator->setMaxDepth($keys_count); 

    $result = array(); 
    foreach ($iterator as $value) { 
     // Skip any level that can never match our keys 
     if ($iterator->getDepth() !== $keys_count) { 
      continue; 
     } 
     // Build key path to current item for comparison 
     $key_path = array(); 
     for ($depth = 1; $depth <= $keys_count; $depth++) { 
      $key_path[] = $iterator->getSubIterator($depth)->key(); 
     } 
     // If key paths match, add to results 
     if ($key_path === $keys) { 
      $result[] = $value; 
     } 
    } 
    return $result; 
} 

爲了使整個事情更加有用,你甚至可以換碼到定製FilterIterator,而不是一個基本功能,但我想這可能是完全不同的問題。

0

我也在我的一個項目中使用一個類似的功能,也許你會發現這個有用:

function extractValuesWithKey($data, $path) { 
     if(!count($path)) return false; 

     $currentPathKey = $path[0]; 

     if(isset($data[$currentPathKey])) { 
      $value = $data[$currentPathKey]; 
      return is_array($value) ? extractValuesWithKey($value, array_slice($path, 1)) : $value; 
     } 
     else { 
      $tmp = array(); 

      foreach($data as $key => $value) { 
       if(is_array($value)) $tmp[] = extractValuesWithKey($value, $path); 
      } 

      return $tmp; 
     } 
    } 
相關問題