本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长

+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

暂无数据

Laravel 5.1 - 集合过滤不起作用

发布于2023-11-29 20:03     阅读(946)     评论(0)     点赞(23)     收藏(1)


我有以下两个集合:

$credits = collect([
   ['quantity' => 3, 'product_id' => 1],
   ['quantity' => 2, 'product_id' => 5]
]);

$basketItems = collect([
   ['id' => 1, 'basket_id' => 4, 'product_id' => 1],
   ['id' => 2, 'basket_id' => 4, 'product_id' => 2],
   ['id' => 3, 'basket_id' => 4, 'product_id' => 1],
   ['id' => 4, 'basket_id' => 4, 'product_id' => 1],
   ['id' => 5, 'basket_id' => 4, 'product_id' => 1]
]);

$credits集合告诉我们用户有 3 个可用积分可用于product_id1 个积分。

现在我想创建两个新的集合。如果用户拥有可用积分的购物篮商品 - 这可以由 Product_id 确定,那么我想将这些商品添加到名为 的新集合中$basketItemsUseCredits

如果购物篮项目没有该产品类型的可用积分,我想将这些项目添加到另一个名为 的集合中$basketItemsPay

因此,在上面的示例中,我最终应该得到$basketItemsUseCreditsid 为 1,3 和 4 的篮子项目。$basketItemsPay最终应该得到 id 为 2 和 5 的篮子项目。以下内容不起作用。

  $basketItemsUseCredits = $basketItems->map(function ($basketItem) use ($credits) {

        $qty = $credits->where('product_id', $basketItem->product_id)->get('quantity', 0);

        if ($qty > 0) {
             // update quantity
             $credits->transform(function ($credit) use ($basketItem) {
                    if ($credit->product_id == $basketItem->product_id) {
                         $credit->quantity = $credit->quantity - 1;
                         return $credit;
                    }
                    else
                        return $credit
            });               

           return $basketItem;
        }
  })


   $basketItemsPay = $basketItems->map(function ($basketItem) use ($basketItemsUseCredits) {

        if (!$basketItemsUseCredits->contains('id', $basketItem->id))
              return $basketItem;
    });

    if(!$basketItemsPay->isEmpty()) {
        // do some extra stuff
    }

以下行始终返回 0:

$qty = $credits->where('product_id', $basketItem->product_id)->get('quantity', 0);

我还注意到另一件事。如果$basketItemsPay为空,例如如果我dd($basketItemsPay)得到以下信息:

Collection {#316 ▼
    #items: array:1 [▼
       0 => null
    ]
 }

那么为什么在上述场景中以下内容总是评估为 true 呢?

if(!$basketItemsPay->isEmpty()) {
        // do some extra stuff
}

任何帮助表示赞赏。

* 更新 *

设法通过执行以下操作来修复 - 除非有人知道更好的解决方案:

$qty = $credits->where('product_id', $basketItem->product_id)->first()['quantity'];

并按如下方式链接拒绝方法以消除空值 - 有人知道更优雅的解决方案吗?

$basketItemsPay = $basketItems->map(function ($basketItem) use ($basketItemsUseCredits) {

      if (!$basketItemsUseCredits->contains('id', $basketItem->id))
             return $basketItem;

})->reject(function ($basketItem) {
        return empty($basketItem);
});

解决方案


我也花了一段时间才弄清楚这一点。下面是我将如何处理这个问题。这是一种稍微更线性的方法,并且比 Collection 方法中的嵌套闭包更不言自明。它的代码也比您的示例多一点,但这是个人喜好的问题。我尝试在代码注释中尽可能具有描述性。

让事情变得更容易的最重要部分在于$credits从一开始就改变集合的结构:

// First, let's simplify the $credits structure for easy checking. NOTE: this collection WILL mutate by the code below.
// If the original version is to be preserved for whatever reason, now's the time to duplicate it :)
$credits = collect([
   ['quantity' => 3, 'product_id' => 1],
   ['quantity' => 2, 'product_id' => 5]
])
    ->pluck('quantity', 'product_id')

/* Results in a collection where keys are product_id, and values are quantity:

    Illuminate\Support\Collection {
        all: [
            1 => 3,
            5 => 2
        ]
    }

*/

$basketItems = collect([
   ['id' => 1, 'basket_id' => 4, 'product_id' => 1],
   ['id' => 2, 'basket_id' => 4, 'product_id' => 2],
   ['id' => 3, 'basket_id' => 4, 'product_id' => 1],
   ['id' => 4, 'basket_id' => 4, 'product_id' => 1],
   ['id' => 5, 'basket_id' => 4, 'product_id' => 1]
]);


$basketItemsUseCredits  = new \Illuminate\Support\Collection;

// First, we will filter the $basketItems collection by the condition that the product_id for each item
// does NOT occur as key inside $credits. NOTE: filter() returns a new collection. The original $basketItems
// does not mutate because of this call.
$basketItemsPay = $basketItems->reject(function ($basketItem) use ($credits) {

    // If credits has a key corresponding the product_id of the current $basketItem, REJECT the $basketItem
    return $credits->has($basketItem['product_id']);
});



// Now, we will create an intermediate collection of basket items that need to be compared against the quantity
// of credits available for products of the ID's present in this collection:
$basketItemsCountCredits = $basketItems->filter(function ($basketItem) use ($credits) {

    // If credits has a key corresponding the product_id of the current $basketItem, KEEP the $basketItem
    return $credits->has($basketItem['product_id']);
});

// Lastly we will iterate the $basketItemsCountCredits collection, and determine whether credits are still available
// for each item. If so, push the item to $basketItemsUseCredits AND decrement the amount of available credits for 
// the item's ID. otherwise just push the item to $basketItemsPay.
foreach ($basketItemsCountCredits as $item) {

    $productId = $item['product_id'];
    $remainingCredits = $credits->get($productId);

    // If more than 0 credits are available for products with ID of $item['product_id']
    if ($remainingCredits > 0) {

        // .. push the $item to $basketItemsUseCredits,
        $basketItemsUseCredits->push($item);

        // .. and decrement the amount of available credits. 
        // Collection->put() overwrites the key => value pair in the collection if the key already exists.
        $credits->put($productId, $remainingCredits - 1);
    } else {

        // The amount of available credits might have become 0 in previous iterations of this for-loop
        $basketItemsPay->push($item);
    }
}

Illuminate Collections 上提供了许多非常强大的方法当以正确的方式使用时,它们可以允许一些非常干净和简洁的代码!

但是,当在不必要的地方使用这些相同的方法时,也会降低代码的可读性和复杂性。在某些情况下,当该回调的定义在其他地方完成并且它依赖于该上下文来完成其工作时,传递回调函数的方法主要有用。从你的例子来看,这里的情况似乎并非如此。

您可以使用旧的 foreach 循环同时执行这两个操作,而不是像我在上面的示例中那样连续使用 和 方法filterreject然而,这确实需要提前将$basketItemsCountCredits$basketItemsPay变量初始化为新集合。如果我们也删除注释,它实际上没有那么多代码,并且仍然完全可读:)

$credits = collect([
   ['quantity' => 3, 'product_id' => 1],
   ['quantity' => 2, 'product_id' => 5]
])->pluck('quantity', 'product_id')

$basketItems = collect([
   ['id' => 1, 'basket_id' => 4, 'product_id' => 1],
   ['id' => 2, 'basket_id' => 4, 'product_id' => 2],
   ['id' => 3, 'basket_id' => 4, 'product_id' => 1],
   ['id' => 4, 'basket_id' => 4, 'product_id' => 1],
   ['id' => 5, 'basket_id' => 4, 'product_id' => 1]
]);


$basketItemsCountCredits = new \Illuminate\Support\Collection;
$basketItemsUseCredits   = new \Illuminate\Support\Collection;
$basketItemsPay          = new \Illuminate\Support\Collection;

// A foreach loop is perfectly sane here
foreach ($basketItems as $item) {
   if ($credits->has($item['product_id'])) {
       $basketItemsCountCredits->push($item);
   } else {
       $basketItemsPay->push($item);
   }
});

foreach ($basketItemsCountCredits as $item) {

    $productId = $item['product_id'];
    $remainingCredits = $credits->get($productId);

    if ($remainingCredits > 0) {
        $basketItemsUseCredits->push($item);
        $credits->put($productId, $remainingCredits - 1);
    } else {
        $basketItemsPay->push($item);
    }
}


所属网站分类: 技术文章 > 问答

作者:黑洞官方问答小能手

链接:http://www.phpheidong.com/blog/article/550180/496df32f5834f0ec6261/

来源:php黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

23 0
收藏该文
已收藏

评论内容:(最多支持255个字符)