Search code examples
phparrayslaravelcollectionsgrouping

Group rows in a collection by specified columns to build a 3d structure


I need to group data from a 2d Laravel query result to form a 3d structure.

In Laravel, my data from ->get()->toArray() result is:

[
    ['ts' => 1234, 'a' => 3, 'b' => 2],
    ['ts' => 1244, 'a' => 2, 'b' => 6],
    ['ts' => 1254, 'a' => 8, 'b' => 3],
]

Is there any way that I am able to transform the data to as such:

[
    ['column' => 'a', 'values' => [[1234, 3], [1244, 2], [1254, 8]],
    ['column' => 'b', 'values' => [[1234, 2], [1244, 6], [1254, 3]],
]

I just wish to know if there's any best / efficient way to render the transformation as described above. Avoid re looping again as data is already available, it can be thought as a data formatting question. Also, I do not wish to use additional array if possible.

Things that I've already looked includes ->get()->map(function()), however this is sequential and I am not able to get values in 2D array as a result.


Solution

  • You'll want to map over your items and return the ts value, as well as the value for each column, respectively:

    $items = Model::all();
    
    $result = [
        [
            'column' => 'a',
            'values' => $items->map(function ($item) {
                return [$item->ts, $item->a];
            })
        ],
        [
            'column' => 'b',
            'values' => $items->map(function ($item) {
                return [$item->ts, $item->b];
            })
        ],
    ];
    

    If you want to combine the logic for both columns, create a collection of column names, and map over those:

    $items = Model::all();
    
    $result = collect(['a', 'b'])->map(function ($column) use ($items) {
        $values = $items->map(function ($item) use ($column) {
            return [$item->ts, $item->{$column}];
        });
    
        return compact('column', 'values');
    });