Make a unique list of values from a particular key existing anywhere in a deep array

核能气质少年 提交于 2019-12-13 00:22:42

问题


I have an array that consists of an undetermined number of arrays, recursively (n levels deep). Each array might contain a name key. I want to create a unique list of those values.

Example

Suppose the array is:

$bigArray = array(
    'name'=>'one', 
    'something'=>array(
        'name'=>'two', 
        'subthing'=>array('name'=>'three')
    ), 
    'anotherthing'=>array('name'=>'one')
);

The expected result would be:

$uniques = array('one', 'two', 'three') // All the 'name' keys values and without duplicates.

Here's a fiddle of my attempt.

My approach was using array_walk_recursive passing a $uniques array as reference, and allowing the function to update that value:

$uniques = array();

function singleOut($item, $key, &$uniques) {
    if ($key == 'name' && !in_array($itm,$uniques,true) )
        $uniques[] = $item;
}

array_walk_recursive($bigArray, 'singleOut', $uniques);

However, it's not working for me.


回答1:


You could use also array_unique on this one too. Example:

$uniques = array();
array_walk_recursive($bigArray, function($val, $key) use (&$uniques){
    if($key == 'name') {
        $uniques[] = $val;
    }
});

$uniques = array_unique($uniques); // unique values



回答2:


Your fiddle was nearly spot on - the problem was, that the user parameter is given by-reference only within same levels of recursion. You need to use indirection with a reference:

$bigArray = array(
    'name'=>'one', 
    'something'=>array(
        'name'=>'two', 
        'subthing'=>array('name'=>'three')
    ), 
    'anotherthing'=>array('name'=>'one')
);

function singleOut($item, $key, $indirect) {
    $uniques=&$indirect[0];
    if ($key == 'name' && !in_array($item,$uniques,true) ) $uniques[] = $item;

}

$uniques = array();
$indirect = array(&$uniques);
array_walk_recursive($bigArray, 'singleOut', $indirect);
print_r($uniques);

Edit:

Fiddle is here




回答3:


To avoid doing an in_array() check inside of array_walk_recursive(), you can store name values as keys in the output array. This will effectively eliminate duplicates by overwriting previous identical keys. When array_walk_recursive() is finished, you can use array_keys() to move the data from keys to values.

Code: (Demo)

$bigArray=[
    'name'=>'one', 
    'something'=>[
        'name'=>'two', 
        'subthing'=>['name'=>'three']
    ], 
    'anotherthing'=>['name'=>'one']
];
array_walk_recursive($bigArray,function($v,$k)use(&$uniques){
    if($k==='name')
        $uniques[$v]='';
});
var_export(array_keys($uniques));

Output:

array (
  0 => 'one',
  1 => 'two',
  2 => 'three',
)

Because array_unique() can be slow in some cases, using array_keys() should generally perform faster. That said, if micro-optimization is a concern then you should do benchmark testing using your actual data and your specific environment and select the best method for your project.

As I mentioned in a comment under Ghost's answer, it is a good habit to make === strict comparisons on keys in your multi-dimensional array because if you are looking for a string, but encounter a 0 key, then PHP's type juggling "feature" will provide unexpected results.

Here is a page where I discuss and demonstrate this behavior: Type juggling while making loose comparison yields unwanted result



来源:https://stackoverflow.com/questions/25634515/make-a-unique-list-of-values-from-a-particular-key-existing-anywhere-in-a-deep-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!