0

How can I group row data from a two-dimensional array and only create a subarray of another column if the respective group contains more than one value?

In other words, I need to group rows by id and conditionally restructure an array of arrays to have a variable depth of either 2 or 3 levels.

Input:

[
    ['id' => 567, 'value' => 780],
    ['id' => 676, 'value' => 743],
    ['id' => 676, 'value' => 721],
    ['id' => 234, 'value' => 766],
    ['id' => 234, 'value' => 680]
]

Desired output:

[
    ['id' => 567, 'value' => 780],
    ['id' => 676, 'value' => [743, 721]],
    ['id' => 234, 'value' => [766, 680]]
]
1

5 Answers 5

2

Are you sure you want to have the value as an integer when there is one value and an array when there are more?

<?php
$array = array(
    array('id' => 567, 'value' => 780),
    array('id' => 676, 'value' => 743),
    array('id' => 676, 'value' => 721),
    array('id' => 234, 'value' => 766),
    array('id' => 234, 'value' => 680)
);

foreach ($array as $item) {
    $result[$item['id']][] = $item['value'];
}

foreach ($result as $id => $value) {
    if (count($value) > 1) {
        $output[] = array(
            'id' => $id,
            'value' => $value
        );
    } else {
        $output[] = array(
            'id' => $id,
            'value' => $value[0]
        );
    }
}

echo '<pre>';
print_r($output);
echo '</pre>';
?>

If not

<?php
$array = array(
    array('id' => 567, 'value' => 780),
    array('id' => 676, 'value' => 743),
    array('id' => 676, 'value' => 721),
    array('id' => 234, 'value' => 766),
    array('id' => 234, 'value' => 680)
);

foreach ($array as $item) {
    $result[$item['id']][] = $item['value'];
}

foreach ($result as $id => $value) {
    $output[] = array(
        'id' => $id,
        'value' => $value
    );
}

echo '<pre>';
print_r($output);
echo '</pre>';
?>
Sign up to request clarification or add additional context in comments.

Comments

0

try this one

$array['key1'] = array(
    0=>array('id'=>567, 'value'=>780),
    1=>array('id'=>676, 'value'=>743),
    2=>array('id'=>676, 'value'=>721),
    3=>array('id'=>234, 'value'=>766),
    4=>array('id'=>234, 'value'=>780)
    );

foreach($array['key1'] as $subarray){
    $group_id = $subarray['id'];

    if(!isset($return[$group_id]))
        $return[$group_id] = $subarray;
    else{
        if(is_array($return[$group_id]['value']))
            array_push($return[$group_id]['value'], $subarray['value']);
        else 
            $return[$group_id]['value'] = array($subarray['value'], $return[$group_id]['value']);
    }
}

// reset grouping keys into 0,1...
$return = array_values($return);
print_r($return);

Comments

0

There, all the work done for you. How easy is that!

//create the array as you have now
$array[0] = ['id'=>567, 'value'=>780];
$array[1] = ['id'=>676, 'value'=>743];
$array[2] = ['id'=>676, 'value'=>721];
$array[3] = ['id'=>234, 'value'=>766];
$array[4] = ['id'=>234, 'value'=>780];

print_r($array);
print chr(10).chr(10);

//create a new array with the values combined on key
$concat = array();
foreach($array as $val) {
  $i = $val['id'];
  $v = $val['value'];

  if (!is_array($concat[$i]))
    $concat[$i] = array();

  $concat[$i][] = $v;
}

print_r($concat);
print chr(10).chr(10);

//create a new array to show the data as you want.
$newarray = array();
foreach($concat as $key=>$val) {
  $t = array();
  $t['id'] = $key;

  if (count($val)==1)
    $t['value'] = $val[0];
  else {
    $t['value'] = array();
    foreach($val as $v)
      $t['value'][] = $v;
  } 

  $newarray[] = $t;
}

print_r($newarray);
print chr(10).chr(10);

Result:

Array
(
    [0] => Array
        (
            [id] => 567
            [value] => 780
        )

    [1] => Array
        (
            [id] => 676
            [value] => 743
        )

    [2] => Array
        (
            [id] => 676
            [value] => 721
        )

    [3] => Array
        (
            [id] => 234
            [value] => 766
        )

    [4] => Array
        (
            [id] => 234
            [value] => 780
        )

)


Array
(
    [567] => Array
        (
            [0] => 780
        )

    [676] => Array
        (
            [0] => 743
            [1] => 721
        )

    [234] => Array
        (
            [0] => 766
            [1] => 780
        )

)


Array
(
    [0] => Array
        (
            [id] => 567
            [value] => 780
        )

    [1] => Array
        (
            [id] => 676
            [value] => Array
                (
                    [0] => 743
                    [1] => 721
                )

        )

    [2] => Array
        (
            [id] => 234
            [value] => Array
                (
                    [0] => 766
                    [1] => 780
                )

        )

)

1 Comment

If you want to edit it, atleast do it right. If you remove the <pre> tags, then the print chr(10).chr(10) lines arent realy needed either anymore. Also I cant realy say you edit made the post any better.
0
<?php
$arr['key1']    = array(
    array(
        'id'    => 567, 
        'value' => 780, 
    ), 
    array(
        'id'    => 676, 
        'value' => 743, 
    ), 
    array(
        'id'    => 676, 
        'value' => 721, 
    ), 
    array(
        'id'    => 234, 
        'value' => 766, 
    ), 
    array(
        'id'    => 234, 
        'value' => 780, 
    ), 
);

/* handle element merge */
function array_internal_merge_func($a, $b) {
    if ( is_array($a['value']) )
        $a['value'][]   = $b['value'];
    else 
        $a['value']     = array($a['value'], $b['value']);
    return $a;
}
/* handle array merge */
function array_internal_merge($array, $key, $merge_func) {
    $hashed = array();
    $result = array();
    foreach ( $array as $idx => $ele ) 
        $hashed[$ele[$key]][]   = $idx;
    foreach ( $hashed as $key => $idxies ) {
        reset($idxies);
        $idx0           = current($idxies);
        $result[$idx0]  = $array[$idx0];
        while ( $idx = next($idxies) ) 
            $result[$idx0]  = $merge_func($result[$idx0], $array[$idx]);
    }
    return $result;
}

print_r(array_internal_merge($arr['key1'], 'id', 'array_internal_merge_func'));

Comments

0

This task can certainly be done concisely with one loop.

Use id column values as temporary first level keys. This makes identifying duplicates most efficient and easy.

While iterating:

  1. if a row's id is new to the result array, then push the whole row (in its original, flat structure) into the result array; or

  2. if a row's id was encountered before, then cast the stored row's value element as an array before pushing the current row's value into that subarray.

If you do not want your result to have id values as the first level keys, then call array_values() to re-index the result.

The special action done implemented below is that when casting a scalar or null data type to an array, the value becomes the lone element of the newly formed array. If an array is explicitly cast as an array, then there is no effect on the data structure at all. This is why (array) can be unconditionally applied in the else branch.

Code: (Demo)

foreach ($array as $row) {
    if (!isset($result[$row['id']])) {
        $result[$row['id']] = $row;
    } else {
        $result[$row['id']]['value'] = array_merge(
            (array) $result[$row['id']]['value'],
            [$row['value']]
        );
    }
}
var_export(array_values($result));

An alternative without array_merge(): (Demo)

foreach ($array as $row) {
    if (!isset($result[$row['id']])) {
        $result[$row['id']] = $row;
    } else {
        $result[$row['id']]['value'] = (array) $result[$row['id']]['value'];
        $result[$row['id']]['value'][] = $row['value'];
    }
}
var_export(array_values($result));

An alternative with array_reduce(): (Demo)

var_export(
    array_values(
        array_reduce(
            $array,
            function($result, $row) {
                if (!isset($result[$row['id']])) {
                    $result[$row['id']] = $row;
                } else {
                    $result[$row['id']]['value'] = (array) $result[$row['id']]['value'];
                    $result[$row['id']]['value'][] = $row['value'];
                }
                return $result;
            }
        )
    )
);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.