Combining two or more arrays into one array according to numeric keys without duplicates in subarrays

248 views Asked by At

I have the following scenario made of arrays with numeric keys. I need to have an array which stores all the values in the arrays grouped by numeric key and without duplicates. I cannot make them strings as they are IDs and need to stay numeric.

Starting point:

    Array
    (
        [77] => Array
            (
                [0] => Bold Condensed
                [1] => Bold Condensed 2
                [2] => Bold Condensed 3
            )
    
    )
    Array
    (
        [77] => Array
            (
                [0] => Bold Condensed
            )
    
        [136] => Array
            (
                [0] => Regular
            )
    
    )
    Array
    (
        [77] => Array
            (
                [0] => Bold Condensed (1, 2, 3)
            )
    
        [168] => Array
            (
                [0] => Regular
                [1] => Bold
            )
    
    )

Expected output:

Array
(
    [77] => Array
        (
            [0] => Bold Condensed
            [1] => Bold Condensed 2
            [2] => Bold Condensed 3
            [3] => Bold Condensed (1 ,2 ,3)
        )

    [136] => Array
        (
            [0] => Regular
        )

    [168] => Array
        (
            [0] => Regular
            [1] => Bold
        )

)

Tried array_merge and array_merge_recursive:

$megaArray = [];

foreach( $arrays as $key => $value) {
  if(array_key_exists($key, $arrays)){
    $megaArray[$key] = array_merge_recursive($value);
  }
}

What I'm getting with both array_merge and array_merge_recursive:

Array
(
    [77] => Array
        (
            [0] => Bold Condensed (1, 2, 3)
        )

    [136] => Array
        (
            [0] => Regular
        )

    [168] => Array
        (
            [0] => Regular
            [1] => Bold
        )

)

Both array_merge() and array_merge_recursive() seem to store the latest value for each key.

6

There are 6 answers

0
Rob Eyre On BEST ANSWER

I think you just need a combination of array_merge and array_unique (since I note you don't have duplicates in your leaf arrays):

$megaArray = [];

foreach ($arrays as $subArray) {
  foreach ($subArray as $key => $value) {
    if (array_key_exists($key, $megaArray)) {
      $megaArray[$key] = array_unique(array_merge($megaArray[$key], $value));
    } else {
      $megaArray[$key] = $value;
    }
  }
}
0
hanif zekri On

Based on your expected output, it seems you need to check key and values at the same time. I write a code that create exact output array like your sample. No need to say that you can use function to simplify the whole process but for understanding the principle of situation, I repeat foreach each time.

$newarray = array();

//-------------
$array1 = array();
$array1[77][0] = 'Bold Condensed';
$array1[77][1] = 'Bold Condensed 2';
$array1[77][2] = 'Bold Condensed 3';

foreach($array1 as $key => $value) {
    if (array_key_exists($key, $newarray)) {
        foreach($value as $subkey => $subvalue) {
            if (!array_key_exists($subkey, $newarray[$key])) {
                $newarray[$key][$subkey] = $subvalue;
            } elseif (array_key_exists($subkey, $newarray[$key]) and $subvalue != $newarray[$key][$subkey]) {
                $newkey = count($newarray[$key]);
                $newarray[$key][$newkey] = $subvalue;
            }
        }
    } else {
        $newarray[$key] = $value;
    }
}

//-------------
$array2 = array();
$array2[77][0] = 'Bold Condensed';
$array2[136][0] = 'Regular';

foreach($array2 as $key => $value) {
    if (array_key_exists($key, $newarray)) {
        foreach($value as $subkey => $subvalue) {
            if (!array_key_exists($subkey, $newarray[$key])) {
                $newarray[$key][$subkey] = $subvalue;
            } elseif (array_key_exists($subkey, $newarray[$key]) and $subvalue != $newarray[$key][$subkey]) {
                $newkey = count($newarray[$key]);
                $newarray[$key][$newkey] = $subvalue;
            }
        }
    } else {
        $newarray[$key] = $value;
    }
}

//-------------
$array3 = array();
$array3[77][0] = 'Bold Condensed (1, 2, 3)';
$array3[168][0] = 'Regular';
$array3[168][1] = 'Bold';

foreach($array3 as $key => $value) {
    if (array_key_exists($key, $newarray)) {
        foreach($value as $subkey => $subvalue) {
            if (!array_key_exists($subkey, $newarray[$key])) {
                $newarray[$key][$subkey] = $subvalue;
            } elseif (array_key_exists($subkey, $newarray[$key]) and $subvalue != $newarray[$key][$subkey]) {
                $newkey = count($newarray[$key]);
                $newarray[$key][$newkey] = $subvalue;
            }
        }
    } else {
        $newarray[$key] = $value;
    }
}

//Final result
print('<pre>'.print_r($newarray, true).'</pre>');
1
nice_dev On

array_merge_recursive is not required since there is only 1 level for each ID and your array_key_exists will always be true since you are getting the same key from foreach and checking on the same array.


You can straightaway get values based on id (which is 77 etc in your case) and keep merging values. You can later array_unique them only once for efficiency and get only unique values for each id.

<?php

$result = [];

foreach($d as $subs){
    foreach($subs as $id => $values){
        $result[ $id ] = array_merge($result[ $id ] ?? [], $values);
    }
}

$result = array_map(fn($v) => array_unique($v), $result);

print_r($result);

Live Demo

1
lukas.j On
foreach ($arrays as $array) {
  foreach ($array as $key => $values) {
    $result[$key] = array_unique(array_merge($result[$key] ?? [], ...[ $values ]));
  }
}
0
Kumara On

here is the code

  <?php
    
    
    // Given arrays
    $array1 = [
        77 => ['Bold Condensed', 'Bold Condensed 2', 'Bold Condensed 3'],
    ];
    
    $array2 = [
        77 => ['Bold Condensed'],
        136 => ['Regular'],
    ];
    
    $array3 = [
        77 => ['Bold Condensed (1, 2, 3)'],
        168 => ['Regular', 'Bold'],
    ];
    
    // Function to merge arrays
    function mergeArrays(...$arrays)
    {
        $result = [];
    
        foreach ($arrays as $array) {
            foreach ($array as $key => $values) {
                if (!isset($result[$key])) {
                    $result[$key] = $values;
                } else {
                    // Merge values, removing duplicates
                    $result[$key] = array_values(array_unique(array_merge($result[$key], $values)));
                }
            }
        }
    
        return $result;
    }
    
    // Merge the arrays
    $mergedArray = mergeArrays($array1, $array2, $array3);
    
    // Output the merged array
    print_r($mergedArray);
    
    ?>

The mergeArrays function will accepts multiple arrays as arguments and merges them into a single result array. It loop through each array, combining values for each key while removing duplicates

0
mickmackusa On

To avoid making evermore expensive array_merge() and array_unique() calls on every iteration of a nested loop, maintain a temporary lookup array and only push unique values into the result array. In other words, don't make a mess for your code to clean up later.

Code: (Demo)

$result = [];
foreach ($arrays as $set) {
    foreach ($set as $id => $row) {
        foreach ($row as $value) {
            if (!isset($lookup[$id][$value])) {
                $lookup[$id][$value] = $value;
                $result[$id][] = $value;
            }
        }
    }
}
var_export($result);

Output:

array (
  77 => 
  array (
    0 => 'Bold Condensed',
    1 => 'Bold Condensed 2',
    2 => 'Bold Condensed 3',
    3 => 'Bold Condensed (1, 2, 3)',
  ),
  136 => 
  array (
    0 => 'Regular',
  ),
  168 => 
  array (
    0 => 'Regular',
    1 => 'Bold',
  ),
)