9

I have been reading about collections in Laravel. Currently I am aware of how to use it however I have a question about the sum() function.

According to the docs it can be used like this:

collect([1, 2, 3, 4, 5])->sum();

And also like this:

$collection = collect([
    ['name' => 'JavaScript: The Good Parts', 'pages' => 176],
    ['name' => 'JavaScript: The Definitive Guide', 'pages' => 1096],
]);

$collection->sum('pages');

Which is fine and I understand, however now I have an array with nested objects and I would like to know how I can achieve something like this in laravel:

$collection = collect([
    ['name' => 'JavaScript: The Good Parts', 'pages' => 176, 'price' => 100.00],
    ['name' => 'JavaScript: The Definitive Guide', 'pages' => price, 'pages' => 150.00],
]);

$collection->sum(['pages', 'prices']);

Which would obviously return either an array like this:

[1272, 250]

or on collection / object like this:

{"total_pages": 1272, "total_price": 250}

in short I would like to know how I can sum and return the results of multiple columns in a laravel collection instead of doing this twice:

$collection->sum('pages');
$collection->sum('price');

Since i assume that would cause multiple loops over the collection or am I wrong?

7
  • Is this to solve a current issue, or just for knowledge? I'm interested in what people come up with Commented Oct 25, 2018 at 16:03
  • Both current issue and knowledge. Commented Oct 25, 2018 at 16:06
  • What's wrong with array-summing and array access? I.e. $sums = $collection->sum(["pages", "prices"]); $pageSum = $sums[0]; $priceSum = $sums[1];? Or are you saying that $collection->sum(["pages", "prices"]); doesn't work? Commented Oct 25, 2018 at 16:27
  • I didn't know that was possible. Commented Oct 25, 2018 at 16:28
  • Your question makes it sound like it is: "$collection->sum(['pages', 'prices']); Which would obviously return either an array like this...", but I get it; that's not supported. Follow-up; what's wrong with a manual loop/addition? Commented Oct 25, 2018 at 16:30

2 Answers 2

10

You would need to use the pipe method to pass the collection to a callback. Within the callback you could achieve what you're wanting to do.

$collection = collect([
    ['name' => 'JavaScript: The Good Parts', 'pages' => 176, 'price' => 100.00],
    ['name' => 'JavaScript: The Definitive Guide', 'pages' => 314, 'price' => 150.00]
]);

$result = $collection->pipe(function ($collection) {
  return collect([
    'total_pages' => $collection->sum('pages'),
    'total_price' => $collection->sum('price'),
  ]);
});
Sign up to request clarification or add additional context in comments.

5 Comments

But won't this just add the sum of book and the sum of prices and return the result?
You're right. I misunderstood your original question. I've updated my answer to do what you'd want.
Wow great, didn't know I can do this! Thank you, going to read more about using pipes!
Have no idea why both my question and yours were down voted though.
Someone else came by and did a random downvote. I upvoted your question to bring it back to 0. Seemed like a legitimate question to me, and I think others will find it useful they google something similar in the future.
3

Looking at the code behind the sum() function, we can see that internally $collection->reduce() is used to collect the data. So we should be able to use the same code to achieve what you are looking for:

return $collection->reduce(function ($result, $item) {
    if ($result === null) {
        $result = [
            'pages' => 0,
            'price' => 0,
        ];
    }

    $result['pages'] += $item['pages'];
    $result['price'] += $item['price'];

    return $result;
}, 0);

To get a more generic solution out of it, you could also create a macro on the Collection class within one of your service providers:

Collection::macro('sumMultiple', function ($columns) {
    return $this->reduce(function ($result, $item) use ($columns) {
        if ($result === null) {
            foreach ($columns as $column) {
                $result[$column] = 0;
            }
        }

        foreach ($columns as $column) {
            $result[$column] += $item[$column];
        }

        return $result;
    }, 0);
});

You can then use the new function with $collection->sumMultiple(['pages', 'price']) and you will receive a result like ['pages' => 123, 'price' => 234].

Pleas be aware that sumMultiple does not support nested arrays at this moment (i.e. dot notation access to fields does not work).

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.