Osvaldo Mercado
Osvaldo Mercado

Reputation: 971

Merge two 2d arrays by shared column value

I know this is quite easily accomplished with a foreach, then a while->list, etc procedure, (I have already accomplished it), however I sense that my code is a bit dirty and it doesn't look like the best solution... I'm looking to use native PHP array functions to do the following:

I have two arrays that look like this:

[
    ['rank' => '579', 'id' => '1'],
    ['rank' => '251', 'id' => '2'],
]

and

[
    ['size' => 'S', 'status' => 'A', 'id' => '1'],
    ['size' => 'L', 'status' => 'A', 'id' => '2'],
]

And I need merge them to produce:

[
    ['size' => 'S', 'status' => 'A', 'id' => '1', 'rank' => '579'],
    ['size' => 'L', 'status' => 'A', 'id' => '2', 'rank' => '251'],
]

Is there a way to be able to merge two arrays with the id value (or any other) without going into a endless set of foreachs?

Upvotes: 10

Views: 69504

Answers (6)

mickmackusa
mickmackusa

Reputation: 47874

It is not necessary to use a recursive technique nor multiple loops. Merge the two arrays together, then assign temporary first-level keys in the output array based on the rows' id value. If the id is being encountered for the first time, merge the row's data with an empty array; otherwise merge the pre-existing row data from result array. To remove the first-level keys after looping, call array_values().

Code: (Demo)

$a = [
    ['rank' => '579', 'id' => '1'],
    ['rank' => '251', 'id' => '2'],
];

$b = [
    ['size' => 'S', 'status' => 'A', 'id' => '1'],
    ['size' => 'L', 'status' => 'A', 'id' => '2'],
];

$result = [];
foreach (array_merge($a, $b) as $row) {
    $result[$row['id']] = $row + ($result[$row['id']] ?? []);
}
var_export(array_values($result));

Not represented by the question's sample data, if the two data sets have columnar data collisions in their respective id group, then later encountered values will overwrite earlier stored values. Demo To reverse that behavior, you can simply swap the data on either side of the "array union operator". Demo Be warned that array union is suitable in this case because the rows contain non-numeric keys. For other scenarios, it may be more reliable to use array_merge() or array_replace() instead of the union operator.

If the relating columns have different names, instead of grouping by $row['id'], cache the grouping value as a variable and fallback to the alternative column name. ($groupKey = $row['id'] ?? $row['otherId'];

Upvotes: 2

nilesh
nilesh

Reputation: 776

function custom_array_merge(&$array1, &$array2) {
    $result = Array();
    foreach ($array1 as $key_1 => &$value_1) {
        // if($value['name'])
        foreach ($array2 as $key_1 => $value_2) {
            if($value_1['name'] ==  $value_2['name']) {
                $result[] = array_merge($value_1,$value_2);
            }
        }

    }
    return $result;
}

// Pass $array1, &$array2 and change the $value_2['name'] // name based on which u want to merge.

Upvotes: 2

gzhegow
gzhegow

Reputation: 53

Have a nice one to merging arrays like another languages. It's because php have auto numbering array elements, and merging will dublicate or replace different elements by keys.

Now, it's changed.

// array_fork
  public static function array_fork() {
    $args = func_get_args();
    $result = array();
    foreach ($args as $arr) {
      is_array($arr) || exit('[' . __METHOD__ . '] Each item must be an array.');
      foreach ($arr as $key => $val) {
        if (is_array($val)) {
          // recursion
          !isset($result[$key]) && $result[$key] = array();
          $result[$key] = self::array_fork($result[$key], $arr[$key]);
          continue;
        }
        if (is_numeric($key)) {
          if (!in_array($arr[$key], $result))
            $result[] = $arr[$key];
        } else
          $result[$key] = $arr[$key];
      }
    }
    return $result;
  }

Upvotes: 2

Martijn
Martijn

Reputation: 5611

As Ray noticed in a comment, the accepted answer does not actually answer the question. I was unable to find an answer, so I created the following small utility function:

function array_merge_callback($array1, $array2, $predicate) {
    $result = array();

    foreach ($array1 as $item1) {
        foreach ($array2 as $item2) {
            if ($predicate($item1, $item2)) {
                $result[] = array_merge($item1, $item2);
            }
        }
    }

    return $result;
}

Use it as follows:

array_merge_callback($array1, $array2, function ($item1, $item2) {
    return $item1['id'] == $item2['id'];
});

Upvotes: 7

Peter
Peter

Reputation: 16923

Use array_merge_recursive()

$array = array_merge_recursive($array1, $array2);

or make your own function (it may be faster)

function my_array_merge(&$array1, &$array2) {
    $result = Array();
    foreach($array1 as $key => &$value) {
        $result[$key] = array_merge($value, $array2[$key]);
    }
    return $result;
}
$array = my_array_merge($array1, array2);
print_r($array);

Upvotes: 16

bigblind
bigblind

Reputation: 12867

ok, let's suppost your arrays are called $arr1 and $arr2, you could do this:

<?php
$newarray = Array();
foreach ($arr1 as $element=>$value){
    $newarray = array_merge($arr1[$element],$arr2[$element])
}
?>

Upvotes: 1

Related Questions