Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.5] groupBy method in collection to support multiple levels #22630

Merged
merged 1 commit into from
Jan 4, 2018
Merged

[5.5] groupBy method in collection to support multiple levels #22630

merged 1 commit into from
Jan 4, 2018

Conversation

patriziotomato
Copy link
Contributor

@patriziotomato patriziotomato commented Jan 4, 2018

Ever wanted to groupBy multiple levels? Simply specify the groupBy-criteria(s) as an array. Each array element will applied for the particular level within a multidimensional tree structure. For each level, the groupBy method works exactly the way before, so you can still use a callback for any level for example.

No clue what I'm talking about? Then take a look at the corresponding test helps maybe:

public function testGroupByMultiLevelAndClosurePreservingKeys()
{
    $data = new Collection([
        10 => ['user' => 1, 'skilllevel' => 1, 'roles' => ['Role_1', 'Role_3']],
        20 => ['user' => 2, 'skilllevel' => 1, 'roles' => ['Role_1', 'Role_2']],
        30 => ['user' => 3, 'skilllevel' => 2, 'roles' => ['Role_1']],
        40 => ['user' => 4, 'skilllevel' => 2, 'roles' => ['Role_2']],
    ]);

    $result = $data->groupBy([
        'skilllevel',
        function ($item) {
            return $item['roles'];
        },
    ], true);

    $expected_result = [
        1 => [
            'Role_1' => [
                10 => ['user' => 1, 'skilllevel' => 1, 'roles' => ['Role_1', 'Role_3']],
                20 => ['user' => 2, 'skilllevel' => 1, 'roles' => ['Role_1', 'Role_2']],
            ],
            'Role_3' => [
                10 => ['user' => 1, 'skilllevel' => 1, 'roles' => ['Role_1', 'Role_3']],
            ],
            'Role_2' => [
                20 => ['user' => 2, 'skilllevel' => 1, 'roles' => ['Role_1', 'Role_2']],
            ],
        ],
        2 => [
            'Role_1' => [
                30 => ['user' => 3, 'skilllevel' => 2, 'roles' => ['Role_1']],
            ],
            'Role_2' => [
                40 => ['user' => 4, 'skilllevel' => 2, 'roles' => ['Role_2']],
            ],
        ],
    ];

    $this->assertEquals($expected_result, $result->toArray());
}

Even cooler if you can combine that with dot-syntax of array_get():

$user40 = array_get($result, '2.Role_2')->first();

…to groupBy an array, each element applies for an level in the returned collection.
@taylorotwell taylorotwell merged commit 4fb6206 into laravel:5.5 Jan 4, 2018
@patriziotomato patriziotomato changed the title groupBy method in collection to support multiple levels [5.5] groupBy method in collection to support multiple levels Jan 4, 2018
@decadence
Copy link
Contributor

@patriziotomato can you explain how works

function ($item) {
    return $item['roles'];
},

if it returns array and not simple value for grouping?

@patriziotomato
Copy link
Contributor Author

@decadence Sorry, don't get your question. $items['roles'] returns an array of roles if you refer to the test testGroupByMultiLevelAndClosurePreservingKeys

@decadence
Copy link
Contributor

Yes. It returns array but doesn't groupBy callback criteria need to return value that can be array key for group? Array can't be array key AFAIK.

@patriziotomato
Copy link
Contributor Author

More precisely a callback function (returning an array) will be passed to groupBy-function. In this case the method behave exactly as it was before my change.

The method then take the array items of the callback function as keys to group by.

This is the relevant part where this magic is happing.

// Here, the group keys of the callback function are used instead of a concrete value.
$groupKeys = $groupBy($value, $key);

if (! is_array($groupKeys)) {
    $groupKeys = [$groupKeys];
}

foreach ($groupKeys as $groupKey) {
	// grouping logic
}

You are right, that passing an array won't work, but in this case the callback is doing the magic. Hope this helps to clarify this.

@decadence
Copy link
Contributor

@patriziotomato thanks for explanation. I didn't know that callback can return array of keys and item will be added to each group for these keys.

@patriziotomato
Copy link
Contributor Author

@decadence Me too ;) Looks like the example in the test is a good one...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants