简体   繁体   中英

PHP - Create a single array from a multidimensional array based on key name

I know there are a lot of answers on multi-dimensional arrays but I couldn't find what I was looking for exactly. I'm new to PHP and can't quite get my head around some of the other examples to modify them. If someone could show me the way, it would be much appreciated.

An external service is passing me the following multidimensional array.

$mArray = Array (
  [success] => 1
  [errors] => 0
  [data] => Array (
    [0] => Array (
      [email] => me@example.com
      [id] => 123456 
      [email_type] => html 
      [ip_opt] => 10.10.1.1 
      [ip_signup] => 
      [member_rating] => X 
      [info_changed] => 2011-08-17 08:56:51 
      [web_id] => 123456789
      [language] =>
      [merges] => Array (
        [EMAIL] => me@example.com
        [NAME] => Firstname 
        [LNAME] => Lastname 
        [ACCOUNT] => ACME Ltd 
        [ACCMANID] => 123456adc 
        [ACCMANTEL] => 1234 123456 
        [ACCMANMAIL] => an.other@example.com
        [ACCMANFN] => Humpty
        [ACCMANLN] => Dumpty 
      )
      [status] => unknown
      [timestamp] => 2011-08-17 08:56:51
      [lists] => Array ( ) 
      [geo] => Array ( ) 
      [clients] => Array ( ) 
      [static_segments] => Array ( )
    ) 
  ) 
)

The only information I'm interested in are the key/value pairs that are held in the array under the key name 'merges'. It's about the third array deep. The key name of the array will always be called merges but there's no guarantee that its location in the array won't be moved. The number of key/value pairs in the merges array is also changeable.

I think what I need is a function for array_walk_recursive($mArray, "myfunction", $search);, where $search holds the string for the Key name (merges) I'm looking for. It needs to walk the array until it finds the key, check that it holds an array and then (preserving the keys), return each key/value pair into a single array.

So, for clarity, the output of the function would return:

    $sArray = Array (
      [EMAIL] => me@example.com
      [NAME] => Firstname 
      [LNAME] => Lastname 
      [ACCOUNT] => ACME Ltd 
      [ACCMANID] => 123456adc 
      [ACCMANTEL] => 1234 123456 
      [ACCMANMAIL] => an.other@example.com 
      [ACCMANFN] => Humpty 
      [ACCMANLN] => Dumpty
    )

I can then move on to the next step in my project, which is to compare the keys in the single merges array to element IDs obtained from an HTML DOM Parser and replace the attribute values with those contained in the single array.

I probably need a foreach loop. I know I can use is_array to verify if $search is an array. It's joining it all together that I'm struggling with.

Thanks for your help.

Would this work?

function find_merges($arr)
{
  foreach($arr as $key => $value){
    if($key == "merges") return $value;
    if(is_array($value)){
      $ret = find_merges($value);
      if($ret) return $ret;
    }
  }
  return false;
}

It would do a depth-first search until you either ran out of keys or found one with the value merges . It won't check to see if merges is an array though. Try that and let me know if that works.

array_walk_recursive() is brilliant for this task! It doesn't care what level the key-value pairs are on and it only iterates the "leaf nodes" so there is not need to check if an element contains a string. Inside of the function, I am merely making a comparison on keys versus the array of needles to generate a one-dimensional result array ( $sArray ).

To be clear, I am making an assumption that you have predictable keys in your merges subarray.

Code: ( Demo )

$needles=['EMAIL','NAME','LNAME','ACCOUNT','ACCMANID','ACCMANTEL','ACCMANMAIL','ACCMANFN','ACCMANLN'];
array_walk_recursive($mArray,function($v,$k)use(&$sArray,$needles){if(in_array($k,$needles))$sArray[$k]=$v;});
var_export($sArray);

Output:

array (
  'EMAIL' => 'me@example.com',
  'NAME' => 'Firstname',
  'LNAME' => 'Lastname',
  'ACCOUNT' => 'ACME Ltd',
  'ACCMANID' => '123456adc',
  'ACCMANTEL' => '1234 123456',
  'ACCMANMAIL' => 'an.other@example.com',
  'ACCMANFN' => 'Humpty',
  'ACCMANLN' => 'Dumpty',
)

A recursive function can do this. Returns the array or FALSE on failure.

function search_sub_array ($array, $search = 'merges') {
  if (!is_array($array)) return FALSE; // We're not interested in non-arrays
  foreach ($array as $key => $val) { // loop through array elements
    if (is_array($val)) { // We're still not interested in non-arrays
      if ($key == $search) {
        return $val; // We found it, return it
      } else if (($result = search_sub_array($array)) !== FALSE) { // We found a sub-array, search that as well
        return $result; // We found it, return it
      }
    }
  }
  return FALSE; // We didn't find it
}

// Example usage
if (($result = search_sub_array($myArray,'merges')) !== FALSE) {
  echo "I found it! ".print_r($result,TRUE);
} else {
  echo "I didn't find it :-(";
}

So you want to access an array within an array within an array?

$mergeArray = NULL;
foreach($mArray['data'] as $mmArray)
    $mergeArray[] = $mmArray['merges'];

Something like that? If merges is always three deep down, I don't see why you need recursion. Otherwise see the other answers.

Here's another approach, mostly because I haven't used up my iterator quota yet today.

$search = new RegexIterator(
    new RecursiveIteratorIterator(
        new ParentIterator(new RecursiveArrayIterator($array)),
        RecursiveIteratorIterator::SELF_FIRST),
    '/^merges$/D', RegexIterator::MATCH, RegexIterator::USE_KEY
);
$search->rewind();
$merges = $search->current();

Here is a general purpose function that will work it's way through a nested array and return the value associated with the first occurance of the supplied key. It allows for integer or string keys. If no matching key is found it returns false.

// return the value a key in the supplied array  
function get_keyval($arr,$mykey)
{  
    foreach($arr as $key => $value){
        if((gettype($key) == gettype($mykey)) && ($key == $mykey)) {
            return $value;
        }
        if(is_array($value)){
            return get_keyval($value,$mykey);               
        }
    }
    return false;
}

// test it out
$myArray = get_keyval($suppliedArray, "merges");
foreach($myArray as $key => $value){
    echo "$key = $value\n";
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM