发布于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_id
1 个积分。
现在我想创建两个新的集合。如果用户拥有可用积分的购物篮商品 - 这可以由 Product_id 确定,那么我想将这些商品添加到名为 的新集合中$basketItemsUseCredits
。
如果购物篮项目没有该产品类型的可用积分,我想将这些项目添加到另一个名为 的集合中$basketItemsPay
。
因此,在上面的示例中,我最终应该得到$basketItemsUseCredits
id 为 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 循环同时执行这两个操作,而不是像我在上面的示例中那样连续使用 和 方法filter
。reject
然而,这确实需要提前将$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黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 php黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-4
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!