Laravel Collection Challenges (Beginner to Advanced)

Before we get into data manipulation using Laravel please note that it’s best to try and use the right tools/technology for what you want to achieve. Laravel’s way to manipulate collection is just one of many ways to manipulate the data. This doesn’t mean you shouldn’t use functions provided by native language and best practices. Sometimes tools as simple as Excel can do the job. Other times a well written SQL query is what’s needed. Then there’s days when you need to use little bit of everything.

Lets get rolling.., shall we?

Note some results are shown in JSON format simply because they are more readable than array on the screen.

Q1. Get sum of the Order. Sum the ‘cost’.

$orderItems = collect([
   ['id' => 1, 'name' => 'Clean Code', 'cost' => 10.99],
   ['id' => 2, 'name' => 'Code Complete', 'cost' => 9.99],
   ['id' => 3, 'name' => 'The Pragmatic Programmer: Your Journey to Mastery', 'cost' => 24.99],
   ['id' => 4, 'name' => 'The Clean Coder: A Code of Conduct for Professional Programmers', 'cost' => 29.99],
   ['id' => 5, 'name' => 'Refactoring', 'cost' => 24.99],
   ['id' => 6, 'name' => 'Head First Design Patterns', 'cost' => 13.99],
]);

Solution:

$orderItems->sum('cost'); // 114.94

Q2. Modify below collection and limit each ‘name’ to 30 words.. so each name looks like this for example:

  • The Clean Coder: A Code of Con..
  • Refactoring…
  • The Pragmatic Programmer: Your…
$orderItems = collect([
   ['id' => 1, 'name' => 'Clean Code', 'cost' => 10.99],
   ['id' => 2, 'name' => 'Code Complete', 'cost' => 9.99],
   ['id' => 3, 'name' => 'The Pragmatic Programmer: Your Journey to Mastery', 'cost' => 24.99],
   ['id' => 4, 'name' => 'The Clean Coder: A Code of Conduct for Professional Programmers', 'cost' => 29.99],
   ['id' => 5, 'name' => 'Refactoring', 'cost' => 24.99],
   ['id' => 6, 'name' => 'Head First Design Patterns', 'cost' => 13.99],
]);

Solution: (map(), change the data and return new array):

$orderItemsToDisplay = $orderItems->map(function($item){
   $item['name'] = substr($item['name'], 0, 30) . '...';

   return $item;
});

Q3. Group below by ‘name’:

$data = collect([
    ['id' => 1, 'name' => 'Clean Code', 'cost' => 10.99],
    ['id' => 2, 'name' => 'Clean Code', 'cost' => 10.99],
    ['id' => 7, 'name' => 'Head First Design Patterns', 'cost' => 13.99],
    ['id' => 8, 'name' => 'Head First Design Patterns', 'cost' => 13.99]
]);

Expected result:

{
  "Clean Code": [
    {
      "id": 1,
      "name": "Clean Code",
      "cost": 10.99
    },
    {
      "id": 2,
      "name": "Clean Code",
      "cost": 10.99
    }
  ],
  "Head First Design Patterns": [
    {
      "id": 7,
      "name": "Head First Design Patterns",
      "cost": 13.99
    },
    {
      "id": 8,
      "name": "Head First Design Patterns",
      "cost": 13.99
    }
  ]
}

Solution:

$data->groupBy('name')

Q4. Put the two collections below into another collection so we have have a single collection with both orders.

$order1Items = collect([
    ['id' => 1, 'name' => 'Clean Code', 'cost' => 10.99],
    ['id' => 2, 'name' => 'Code Complete', 'cost' => 9.99],
]);

$order2Items = collect([
    ['id' => 4, 'name' => 'The Clean Coder: A Code of Conduct for Professional Programmers', 'cost' => 29.99],
    ['id' => 5, 'name' => 'Refactoring', 'cost' => 24.99],
]);

Solution:

$orders = collect();
$orders->push($order1Items, $order2Items);

Q5. Add ‘slug’ as each order’s key. Use ‘name’ to generate slug:

$data = collect([
    ['id' => 1, 'name' => 'Clean Code', 'cost' => 10.99],
    ['id' => 2, 'name' => 'Clean Code', 'cost' => 10.99],
    ['id' => 7, 'name' => 'Head First Design Patterns', 'cost' => 13.99],
    ['id' => 8, 'name' => 'Head First Design Patterns', 'cost' => 13.99]
]);

Solution:

$newColl = $data->map(function($item){
    $item['slug'] = Str::slug($item['name']);
    
    return $item;
});
[
  {
    "id": 2,
    "name": "Clean Code",
    "cost": 10.99,
    "slug": "clean-code"
  },
  {
    "id": 7,
    "name": "Head First Design Patterns",
    "cost": 13.99,
    "slug": "head-first-design-patterns"
  }
]

Q6. Filter the items returning orders over the cost of 10.

$data = collect([
    ['id' => 1, 'name' => 'Clean Code', 'cost' => 9.99],
    ['id' => 2, 'name' => 'Clean Code 2', 'cost' => 10.99],
    ['id' => 7, 'name' => 'Head First Design Patterns', 'cost' => 8.99],
    ['id' => 8, 'name' => 'Head First Design Patterns revised version', 'cost' => 13.99]
]);

Solution:

$res = $data->filter(function($item){
    return $item['cost'] > 10;
});
{
  "1": {
    "id": 2,
    "name": "Clean Code 2",
    "cost": 10.99
  },
  "3": {
    "id": 8,
    "name": "Head First Design Patterns revised version",
    "cost": 13.99
  }
}

Q7. Rewrite Q6 solution so it returns objects without keys:

{
  "1": {
    "id": 2,
    "name": "Clean Code 2",
    "cost": 10.99
  },
  "3": {
    "id": 8,
    "name": "Head First Design Patterns revised version",
    "cost": 13.99
  }
}

Solution:

$data = collect([
    ['id' => 1, 'name' => 'Clean Code', 'cost' => 9.99],
    ['id' => 2, 'name' => 'Clean Code 2', 'cost' => 10.99],
    ['id' => 7, 'name' => 'Head First Design Patterns', 'cost' => 8.99],
    ['id' => 8, 'name' => 'Head First Design Patterns revised version', 'cost' => 13.99]
]);
    
$res = $data->filter(function($item){
    return $item['cost'] > 10;
});

return $res->values();

Q8. Remove ‘id’ from below collection:

$data = collect([
    ['id' => 1, 'name' => 'Clean Code', 'cost' => 9.99],
    ['id' => 2, 'name' => 'Clean Code 2', 'cost' => 10.99],
    ['id' => 7, 'name' => 'Head First Design Patterns', 'cost' => 8.99],
    ['id' => 8, 'name' => 'Head First Design Patterns revised version', 'cost' => 13.99]
]);

Solution:

$res = $data->map(function ($item) {
    unset($item['id']);

    return $item;
});
[
  {
    "name": "Clean Code",
    "cost": 9.99
  },
  {
    "name": "Clean Code 2",
    "cost": 10.99
  },
  {
    "name": "Head First Design Patterns",
    "cost": 8.99
  },
  {
    "name": "Head First Design Patterns revised version",
    "cost": 13.99
  }
]

You can do same in plain PHP too using array_map() function which accepts an array instead of a collection:

$data = [
    ['id' => 1, 'name' => 'Clean Code', 'cost' => 9.99],
    ['id' => 2, 'name' => 'Clean Code 2', 'cost' => 10.99],
    ['id' => 7, 'name' => 'Head First Design Patterns', 'cost' => 8.99],
    ['id' => 8, 'name' => 'Head First Design Patterns revised version', 'cost' => 13.99]
];

$res = array_map(function($item){
    unset($item['id']);

    return $item;
}, $data);

Q9. Get order total without VAT (20%):

$order = collect([
    ['id' => 1, 'name' => 'Clean Code', 'cost' => 9.99],
    ['id' => 2, 'name' => 'Clean Code 2', 'cost' => 10.99],
    ['id' => 7, 'name' => 'Head First Design Patterns', 'cost' => 8.99],
    ['id' => 8, 'name' => 'Head First Design Patterns revised version', 'cost' => 13.99]
]);

Solution:

$vat = $order->sum('cost') * 0.2;
$total = $order->sum('cost') - $vat;

Q10. Get order total (note the additional ‘qty’ value):

$order = collect([
    ['id' => 1, 'name' => 'Clean Code', 'cost' => 9.99, 'qty' => 1],
    ['id' => 2, 'name' => 'Clean Code 2', 'cost' => 10.99, 'qty' => 1],
    ['id' => 7, 'name' => 'Head First Design Patterns', 'cost' => 8.99, 'qty' => 1],
    ['id' => 8, 'name' => 'Head First Design Patterns revised version', 'cost' => 13.99, 'qty' => 2]
]);

Solution:

$total = $order->sum(function($item){
    return $item['cost'] * $item['qty'];
});

In SQL you could just do something like this SELECT sum(cost*qty) from table_name;

Q11. Customer is refunded some books from below order. See ‘refunds’ array containing refunded books ids. Get the order items excluding refunded books.

$order = collect([
    ['id' => 1, 'name' => 'Clean Code', 'cost' => 9.99, 'qty' => 1],
    ['id' => 2, 'name' => 'Clean Code 2', 'cost' => 10.99, 'qty' => 1],
    ['id' => 7, 'name' => 'Head First Design Patterns', 'cost' => 8.99, 'qty' => 1],
    ['id' => 8, 'name' => 'Head First Design Patterns revised version', 'cost' => 13.99, 'qty' => 2]
]);

$refunds = [1, 2, 7];

Expected response:

{
  "3": {
    "id": 8,
    "name": "Head First Design Patterns revised version",
    "cost": 13.99,
    "qty": 2
  }
}

Solution:

$resp = $order->filter(function($item) use ($refunds){
    return array_search($item['id'], $refunds) === false;
});

Q12. Customer is refunded a book from below order. See ‘refunds’ array containing refunded book id. Get sum of the order excluding the refunded book(s).

$order = collect([
    ['id' => 1, 'name' => 'Clean Code', 'cost' => 9.99, 'qty' => 1],
    ['id' => 2, 'name' => 'Clean Code 2', 'cost' => 10.99, 'qty' => 1],
    ['id' => 7, 'name' => 'Head First Design Patterns', 'cost' => 8.99, 'qty' => 1],
    ['id' => 8, 'name' => 'Head First Design Patterns revised version', 'cost' => 13.99, 'qty' => 2]
]);

$refunds = [1];

Solution

$resp = $order->sum(function($item) use($refunds){
    if(array_search($item['id'], $refunds) === false) {
        return $item['cost'] * $item['qty'];
    }
});

Q13. Find out the difference between current price of an item and the paid amount it (you can see price of the purchased item went up from 15.99 to 17.99).

$order = ['item_id' => 8, 'name' => 'Head First Design Patterns revised version', 'paid' => 15.99];

$items = collect([
    ['item_id' => 1, 'name' => 'Clean Code', 'cost' => 9.99],
    ['item_id' => 2, 'name' => 'Clean Code 2', 'cost' => 10.99],
    ['item_id' => 7, 'name' => 'Head First Design Patterns', 'cost' => 8.99],
    ['item_id' => 8, 'name' => 'Head First Design Patterns revised version', 'cost' => 17.99]
]);

Solution:

$itemCost = $items->where('item_id', $order['item_id'])->first()['cost'];

$diff = $itemCost - $order['paid'];

Q14. Find out the difference between current price of the items and the paid amount. This time there’s multiple orders, what’s the total difference?

$order = collect([
    ['item_id' => 8, 'name' => 'Head First Design Patterns revised version', 'paid' => 15.99],
    ['item_id' => 2, 'name' => 'Clean Code 2', 'paid' => 6.99]
]);

$items = collect([
    ['item_id' => 1, 'name' => 'Clean Code', 'cost' => 9.99],
    ['item_id' => 2, 'name' => 'Clean Code 2', 'cost' => 10.99],
    ['item_id' => 7, 'name' => 'Head First Design Patterns', 'cost' => 2.99],
    ['item_id' => 8, 'name' => 'Head First Design Patterns revised version', 'cost' => 17.99]
]);

Solution:

$orderTotal = $order->sum('paid');
$costs = $items->whereIn('item_id', $order->pluck('item_id'))->sum('cost');
$diff = $costs - $orderTotal;

Leave a comment

Your email address will not be published. Required fields are marked *