I'll-Be-Back
I'll-Be-Back

Reputation: 10828

Check if a collection contain another collection?

Using Laravel Collection, what the good way to check if check if a collection ($selectedItems) contain another collection ($orders)?

I am currently using two foreach loop $selectedItems and check if it exist in the $orders using another loop.

   $selectedItems = collect([
        ["ItemId" => "T123", "Price" => "12.00"],
        ["ItemId" => "T99", "Price" => "13.00"],
    ]);

    $orders = collect([
        ["ItemId" => "T123", "Cost" => "12.00"],
        ["ItemId" => "T99", "Cost" => "13.00"],
        ["ItemId" => "T33", "Cost" => "13.00"],
    ]);

    $found = [];

    foreach ($selectedItems as $selectedItem)
    {
        foreach($orders as $orderItem)
        {
            if ($orderItem['ItemId'] !== $selectedItem['ItemId']) {
                continue;
            }

            $found[] = $orderItem;
        }
    }


    if (count($found) == $selectedItems->count()) {
        dd("Matched");
    } else {
        dd("Not Matched");
    }

How to also ensure the Price from $selectedItems is the same as Cost in the $orders

Upvotes: 4

Views: 3941

Answers (5)

Aamir
Aamir

Reputation: 41

$selectedItems->diff($orders)->isEmpty();

This will diff the second collection from the first and if the result is empty you can be sure that all your items exist in the other collection.

Upvotes: 4

ChronoFish
ChronoFish

Reputation: 3707

$matched = $selectedItems->intersect($orders)->count() == $selectedItems->count();

Intersect returns a collection of selectedItems found in Orders. When the count of this intersection == the count of the selectedItems then we know all selectedItems are in the interesected collection (and therefore all selectedItems are in Orders).

Upvotes: 1

eaglebeagle2
eaglebeagle2

Reputation: 98

What you want is the union collection function.

It merges the collections and gives you a unique subset of results. Meaning that duplicates are removed. This way you don't have to check if one exists in the other, just that you have a collection with unique values.

Read more about the union function here

Edit: Because I misunderstood the intent of the original here is an answer that more correctly matches the intent.

$found = [];
$selectedItems->contains(function ($value, $key) use ($found){
    if($orders->contains($value)) {
        $found += [$key => $value]
    }
})

Upvotes: 1

Rafael
Rafael

Reputation: 1535

I took a different approach than you to check if the $orders items keys are contained inside $selectedItems. But I think I got the expected result.

I created this function wrapping the code dealing with only this two arrays.

function checkContainsOrders($selectedItems, $orders)
{
    //Commenting this lines that are necessary only for Laravel Collection
    //$selectedItems = $selectedItems->toArray();
    //$orders = $orders->toArray();

    $selectedItemsKeys = array_column($selectedItems, 'ItemId');
    $orderItemsKeys = array_column($orders, 'ItemId');

    $intersectedValues = array_intersect($selectedItemsKeys, $orderItemsKeys);

    if (count($intersectedValues) === count($selectedItems) || count($intersectedValues) === count($orders)) {
        echo 'yup';
    } else {
        echo 'nope';
    }
}

You can see that I'm making use of array_column to extract only the column I want from both arrays and array_intersect for finding the matches between both.

My data is declared as arrays only:

$selectedItems = [
    ["ItemId" => "T123", "Price" => "12.00"],
    ["ItemId" => "T99", "Price" => "13.00"],
];

$orders = [
    ["ItemId" => "T123", "Cost" => "12.00"],
    ["ItemId" => "T99", "Cost" => "13.00"],
    ["ItemId" => "T33", "Cost" => "13.00"],
];

But you can easily convert a collection to an array using the method toArray() as I commented in the code.

Then finally executing and validating the result.

checkContainsOrders($selectedItems, $orders);

This code has been tested here: https://3v4l.org/JlCC8

Upvotes: 0

Teoman Tıngır
Teoman Tıngır

Reputation: 2866

$selectedItems = collect([
        ["ItemId" => "T123", "Price" => "12.00"],
        ["ItemId" => "T99", "Price" => "13.00"],
    ]);

    $orders = collect([
        ["ItemId" => "T123", "Cost" => "12.00"],
        ["ItemId" => "T99", "Cost" => "13.00"],
        ["ItemId" => "T33", "Cost" => "13.00"],
    ]);
// get orders and selected items ids as an array
    $ordersIds = array_map('array_shift', $orders->toArray());
    $selectedItemIds = array_map('array_shift', $selectedItems->toArray());
// check selected items ids exist in orders ids    
    $exist = count(array_intersect($selectedItemIds, $ordersIds)) == count($selectedItemIds);
// if exist, return true
    if ($exist)
        return true;

Upvotes: 0

Related Questions