Nawin
Nawin

Reputation: 1692

Array merge with same keys

I have these three arrays:

Array
(
    [1] => [email protected]
    [2] => [email protected]
    [3] => [email protected]
)

Array
(
    [1] => 
    [2] => 4234235
    [3] => 
)

Array
(
    [2] => 1
)

And I want to generate this output:

Array
(
    [1] => array(
            [0] => [email protected]
            )
    [2] => array(
            [0] => [email protected]
            [1] => 4234235
            [2] => 1
            )
    [3] => array(
            [0] => [email protected]
            )
)

I need some assistance because I already researched array_merge_recursive() and array_merge(), but I can't get the correct result.

If I need to use foreach() what must I do to merge these 3 arrays.

Upvotes: 0

Views: 2267

Answers (2)

mickmackusa
mickmackusa

Reputation: 48051

As you have no doubt discovered, array_merge_recursive() stubbornly smashes all numeric or "numeric string" keys into a 1-dimensional array. To avoid this behavior, you need to cast each of your arrays' initial keys as strings in a way that will not be assumed to be a number by array_merge_recursive().

Additionally you want to filter out all elements that have empty values.

I initially wrote a one-liner that performed the key re-casting then filtered the values, but it is less efficient that way. For your case, you should only use array_filter() on arrays that may possibly contain empty values.

Input Arrays:

$a=[1=>"[email protected]",2=>"[email protected]",3=>"[email protected]"];
$b=[1=>"",2=>"4234235",3=>""]; 
$c=[2=>1];

Code:

// remove empty values from all arrays that may have them
$b=array_filter($b,'strlen');

// for all arrays, cast numeric keys to string by prepending with a space
function addK($v){return " $v";}
$a=array_combine(array_map('addK',array_keys($a)),$a);
$b=array_combine(array_map('addK',array_keys($b)),$b);
$c=array_combine(array_map('addK',array_keys($c)),$c);

// merge arrays recursively
$merged=array_merge_recursive($a,$b,$c);

// cast keys back to numeric
$merged=array_combine(array_map('trim',array_keys($merged)),$merged);

// force all top-level elements to be arrays
foreach($merged as $k=>$v){
    if(is_string($merged[$k])){$merged[$k]=[$v];}
}

var_export($merged);

Output:

array (
    1 => array (
        0 => '[email protected]',
    ),
    2 => array (
        0 => '[email protected]',
        1 => '4234235',
        2 => 1,
    ),
    3 => array (
        0 => '[email protected]',
    ),
)

For readers who want to know the difference when array_merge_recursive() is run with no preparation:

array (
  0 => '[email protected]',
  1 => '[email protected]',
  2 => '[email protected]',
  3 => '',
  4 => '4234235',
  5 => '',
  6 => 1,
)

Notice the 1d array and the re-indexed keys? ...totally useless for the OP.

Finally, for anyone who wants to re-cast the keys to all arrays and would like to make my process more DRY, there may be an opportunity to set up a variadic function or similar. I merely didn't bother to pursue the notion because I didn't want to make my answer anymore complex and it is not a terrible amount of Repeating Myself.

Upvotes: 1

katona.abel
katona.abel

Reputation: 771

Wrote a little script:

$a = array
(
    1=>"[email protected]",
    2=>"[email protected]",
    3=>"[email protected]",
);

$b = array
(
    2 => 4234235 
);

$c = array
(
    2 => 1
);

$arrayKeys = array_unique(
    array_merge(
        array_keys($a),
        array_keys($b),
        array_keys($c)
    )
);

$d = array_combine(
    $arrayKeys,
    array_fill(
        0,
        count($arrayKeys),
        array()
    )
);

foreach($a as $key => $value) {
    if(!empty($a[$key])) {
        $d[$key][] = $a[$key];
    }
    if(!empty($b[$key])) {
        $d[$key][] = $b[$key];
    }
    if(!empty($c[$key])) {
        $d[$key][] = $c[$key];
    }
}
var_dump($d);

Also if you want to you can merge together the arrays using the variable names only

//names of the variables to merge together
$arrayVariableNames = array("a","b","c");

//merging array keys together
$arrayKeys = array();
foreach($arrayVariableNames as $variableName) {
    $arrayKeys = array_merge(
        $arrayKeys,
        array_keys(${$variableName})
    );
}
$arrayKeys = array_unique($arrayKeys);

//initialize the result array with empty arrays
$resultArray = array_combine(
    $arrayKeys,
    array_fill(
        0,
        count($arrayKeys),
        array()
    )
);

//loop through all the keys and add the elements from all the arrays
foreach($resultArray as $key => &$value) {
    foreach($arrayVariableNames as $variableName) {
        if(!empty(${$variableName}[$key])) {
            $value[] = ${$variableName}[$key];
        }
    }
}

Upvotes: 4

Related Questions