2

I want to merge a multidimensional array values if the values are the same under the 'u','v' and 'w' keys.

$myarray = array (
  '0' => 
    array (
      'u' => '30', 
      'v' => '16', 
      'w' => '22',        
      'x' => '30', 
      'y' => '16', 
      'z' => '22',  
),
  '1' => 
    array (
      'u' => '32', 
      'v' => '25', 
      'w' => '1',        
      'x' => '30', 
      'y' => '16', 
      'z' => '22',
),   
  '2' => 
    array (
      'u' => '30', 
      'v' => '16', 
      'w' => '22',        
      'x' => '54', 
      'y' => '96', 
      'z' => '2',
),   
  '3' => 
    array (
      'u' => '30', 
      'v' => '16', 
      'w' => '22',        
      'x' => '3', 
      'y' => '1', 
      'z' => '6',
)    
); 

I want the output to be as below:

//OUTPUT

array (
  '0' => 
    array (
      'u' => '30', 
      'v' => '16', 
      'w' => '22',        
      'x' => '30,54,3', 
      'y' => '16,96,1', 
      'z' => '22,2,6',  
),
  '1' => 
    array (
      'u' => '32', 
      'v' => '25', 
      'w' => '1',        
      'x' => '30', 
      'y' => '16', 
      'z' => '22',
)   
) 

This is what I have tried to do so far, which has not worked out for me.

<?php
$n = 0;            
$output = [];
foreach ($myarray as $row) {
    
    $prevkey = key(array_slice($output, -1,1,true));// get previous array key    
    
    if(array_key_exists('0', $output)){
        
        if($output[$prevkey]['u'] == $row['u'] && $output[$prevkey]['v'] == $row['v'] &&   $output[$prevkey]['w'] == $row['w'] ){
            echo "yes <br>";
           $output += $row;
        }
        
    }else{
      $output[] = $row;  
    }
    $n++;
}

var_dump($output); 
?>
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Dslide
  • 25
  • 3
  • Very related: [Group rows of a multidimensional array and form comma-separated values within each group](https://stackoverflow.com/q/14255369/2943403) – mickmackusa Apr 08 '23 at 10:36
  • Virtual duplicate: [Group 2d array by column value and concatenate values within each group](https://stackoverflow.com/q/44962581/2943403) – mickmackusa Apr 08 '23 at 13:13

3 Answers3

0

You can create some specific array for that purpose with its specific indexes, based on those 3 values. For ex.:

$myarray = [...];

$supp = [];
foreach ($myarray as $ind => $arr){

    // remember 3 values and use them as a new index
    $uvw = sprintf('%d|%d|%d', $arr['u'], $arr['v'], $arr['w']); 

    if (!isset($supp[$uvw])){
        $supp[$uvw] = ['ind' => $ind, 'data' => $arr];
    } else {
         
        foreach($arr as $in => $new_val){ 
            foreach($supp[$uvw]['data'] as $i => &$val){
                if ($i === $in && !in_array($i,['u','v','w'])){
                    $val .= ',' . $new_val;
                }
            }
        }
    }
}

// recombine the output data (it also includes the parent index value)
$output = [];
foreach($supp as $arr_data){
    $output[$arr_data['ind']] = $arr_data['data'];
}

print_r($output);

Output:

Array
(
    [0] => Array
        (
            [u] => 30
            [v] => 16
            [w] => 22
            [x] => 30,54,3
            [y] => 16,96,1
            [z] => 22,2,6
        )

    [1] => Array
        (
            [u] => 32
            [v] => 25
            [w] => 1
            [x] => 30
            [y] => 16
            [z] => 22
        )

)

Demo

Aksen P
  • 4,564
  • 3
  • 14
  • 27
0

You can use array_reduce:

$grouped = array_reduce($myarray, function ($result, $item) {
    $key = '';
    foreach (['u', 'v', 'w'] as $prop) {
        $key .= $item[$prop] . '_';
    }
    if (array_key_exists($key, $result)) {
        foreach (['x', 'y', 'z'] as $prop) {
            $result[$key][$prop] .= ',' . $item[$prop];
        }
    } else {
        $result[$key] = $item;
    }
    return $result;
}, []);

$result = array_values($grouped);

Working example

protob
  • 3,317
  • 1
  • 8
  • 19
0

This grouping by multiple columns can be done in a single loop without needing to reindex at the end if reference variables are pushed into the result array.

vsprintf() is an easy way to create a delimited string fron the first 3 values in each row -- if you need to explicitly name the identifying keys because they are not reliably first in the rows, then you can manually access them to building the composite key.

Concatenation is only performed if a group is encountered more than once.

Code: (Demo)

$result = [];
foreach ($array as $row) {
    $key = vsprintf('%d_%d_%d', $row);
    if (!isset($ref[$key])){
        $ref[$key] = $row;
        $result[] = &$ref[$key];
    } else {
        $ref[$key]['x'] .= ',' . $row['x'];
        $ref[$key]['y'] .= ',' . $row['y'];
        $ref[$key]['z'] .= ',' . $row['z'];
    }
}
var_export($result);
mickmackusa
  • 43,625
  • 12
  • 83
  • 136