Home > Net >  Group multidimensional arrays by key
Group multidimensional arrays by key

Time:03-05

I'm stuck on this problem and I hope someone can help me on that. I have an array which I want to group by a specific key. The only problem is that I want to have a new array whenever the value of the key changes during the loop. Here is an example of the array.

Array
(
    [0] => Array
        (
            [id] => 972
            [user_id] => 2
            [user_field_48] => 1
            [project] => 100 — NLO
            [duration] => 1:00
            [grouped_by] => 1
        )

    [1] => Array
        (
            [id] => 644
            [user_id] => 2
            [user_field_48] => 4
            [project] => 123 — QHV
            [duration] => 15:00
            [grouped_by] => 4
        )

    [2] => Array
        (
            [id] => 631
            [user_id] => 2
            [user_field_48] => 4
            [project] => 
            [duration] => -5:00
            [grouped_by] => 4
        )

    [3] => Array
        (
            [id] => 630
            [user_id] => 2
            [user_field_48] => 1
            [project] => 
            [duration] => 22:00
            [grouped_by] => 1
        )

    [4] => Array
        (
            [id] => 971
            [user_id] => 2
            [user_field_48] => 1
            [project] => 100 — NLO
            [duration] => 1:00
            [grouped_by] => 1
        )

    [5] => Array
        (
            [id] => 973
            [user_id] => 2
            [user_field_48] => 1
            [project] => 100 — NLO
            [duration] => 1:00
            [grouped_by] => 1
        )

    [6] => Array
        (
            [id] => 974
            [user_id] => 2
            [user_field_48] => 1
            [project] => 100 — NLO
            [duration] => 1:00
            [grouped_by] => 1
        )

)

I did

foreach($report_items as $item)
{
    $groupedItems[$item['grouped_by']][] = $item;
}

and I got

Array
(
    [1] => Array
        (
            [0] => Array
                (
                    [id] => 972
                    [user_id] => 2
                    [user_field_48] => 1
                    [project] => 100 — NLO
                    [duration] => 1:00
                    [grouped_by] => 1
                )

            [1] => Array
                (
                    [id] => 630
                    [user_id] => 2
                    [user_field_48] => 1
                    [project] => 
                    [duration] => 22:00
                    [grouped_by] => 1
                )

            [2] => Array
                (
                    [id] => 971
                    [user_id] => 2
                    [user_field_48] => 1
                    [project] => 100 — NLO
                    [duration] => 1:00
                    [grouped_by] => 1
                )

            [3] => Array
                (
                    [id] => 973
                    [user_id] => 2
                    [user_field_48] => 1
                    [project] => 100 — NLO
                    [duration] => 1:00
                    [grouped_by] => 1
                )

            [4] => Array
                (
                    [id] => 974
                    [user_id] => 2
                    [user_field_48] => 1
                    [project] => 100 — NLO
                    [duration] => 1:00
                    [grouped_by] => 1
                )

        )

    [4] => Array
        (
            [0] => Array
                (
                    [id] => 644
                    [user_id] => 2
                    [user_field_48] => 4
                    [project] => 123 — QHV
                    [duration] => 15:00
                    [grouped_by] => 4
                )

            [1] => Array
                (
                    [id] => 631
                    [user_id] => 2
                    [user_field_48] => 4
                    [project] => 
                    [duration] => -5:00
                    [grouped_by] => 4
                )

        )

)

What I'm actually looking for is something like this, where the arrays are separated during the loop and a suffix is added to the key whenever the value changes.

Array
(
    [1.1] => Array
        (
            [0] => Array
                (
                    [id] => 972
                    [user_id] => 2
                    [user_field_48] => 1
                    [project] => 100 — NLO
                    [duration] => 1:00
                    [grouped_by] => 1
                )
        )

    [4.1] => Array
        (
            [0] => Array
                (
                    [id] => 644
                    [user_id] => 2
                    [user_field_48] => 4
                    [project] => 123 — QHV
                    [duration] => 15:00
                    [grouped_by] => 4
                )

            [1] => Array
                (
                    [id] => 631
                    [user_id] => 2
                    [user_field_48] => 4
                    [project] => 
                    [duration] => -5:00
                    [grouped_by] => 4
                )

        )

    [1.2] => Array
        (
            [0] => Array
                (
                    [id] => 630
                    [user_id] => 2
                    [user_field_48] => 1
                    [project] => 
                    [duration] => 22:00
                    [grouped_by] => 1
                )

            [1] => Array
                (
                    [id] => 971
                    [user_id] => 2
                    [user_field_48] => 1
                    [project] => 100 — NLO
                    [duration] => 1:00
                    [grouped_by] => 1
                )

            [2] => Array
                (
                    [id] => 973
                    [user_id] => 2
                    [user_field_48] => 1
                    [project] => 100 — NLO
                    [duration] => 1:00
                    [grouped_by] => 1
                )

            [3] => Array
                (
                    [id] => 974
                    [user_id] => 2
                    [user_field_48] => 1
                    [project] => 100 — NLO
                    [duration] => 1:00
                    [grouped_by] => 1
                )

        )
        
)

I'm not really aware of a simple way to solve this, so I would appreciate any help. Thank you!

CodePudding user response:

Not going to bother to recreate your full array here, I am using a reduced version with just the id and the grouped_by value, but the principle is of course exactly the same if you do it with your "full" array.

I am using a counter array to keep track of which "iteration" of a specific group we are currently dealing with. In classic control break implementation logic, I am comparing the grouped_by of the current record, with that of the previous one - if those differ, then the counter for this grouped_by value has to be incremented by 1. And then, I am simply creating the array key to use, by combining the grouped_by value, and the current count for it.

$data = [['id' => 972, 'grouped_by' => 1], ['id' => 664, 'grouped_by' => 4], ['id' => 631, 'grouped_by' => 4], ['id' => 630, 'grouped_by' => 1], ['id' => 971, 'grouped_by' => 1], ['id' => 973, 'grouped_by' => 1], ['id' => 974, 'grouped_by' => 1]];

$grouped_result = $grouped_by_counts = [];
$previous_grouped_by = null; // a value that will never occur in the data

foreach($data as $datum) {
    if($datum['grouped_by'] !== $previous_grouped_by) {
        $grouped_by_counts[$datum['grouped_by']] =
          isset($grouped_by_counts[$datum['grouped_by']]) ? 
          $grouped_by_counts[$datum['grouped_by']]   1 : 1;
    }
    $grouped_result[
      $datum['grouped_by'].'.'.$grouped_by_counts[$datum['grouped_by']]
    ][] = $datum;
    $previous_grouped_by = $datum['grouped_by'];
}

print_r($grouped_result);

Live example: https://3v4l.org/odtie

  • Related