我必须编写“以X支付Y付款”算法。 到达我端点的请求是文章列表
public class Article
{
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
}
payFor变量来自db,由包折扣ID定义
这是我到目前为止编写的算法
if (purchasedQuantity >= minPurchaseQuantity)
{
var c = 0;
foreach (var article in articlesForPackage.OrderByDescending(a => a.UnitPrice))
{
for (var i = 1; i <= article.Quantity; i++)
{
c++;
if (c > payFor)
{
c = 0;
result.Add(new Discount
{
Value = article.UnitPrice
});
}
}
}
}
不幸的是,该算法在某些情况下不起作用。
定义了套餐折扣后,买3付2钱就可以了,但是如果买3付1钱就不起作用了。 有人可以帮我吗?
这是算法的工作方式: 我们有3篇文章 1艺术作品1-20 $ 2 Art2-30 $ 3 Art3-40 $
如果minPurchaseQuantity为3,而payFor为2,则意味着应将Art1的成本添加到结果列表中(因为它是最便宜的)
如果minPurchaseQuantity为3且payFor为1,则意味着应将Art2和Art1的成本添加到结果列表中(现在仅添加Art2)
答案 0 :(得分:1)
好吧,主要的问题是,一旦c
大于payFor
,就将其重置。只要minPurchaseQuantity-payFor=1
都可以使用,但是在其他情况下无效。
虽然这不如我在第一个答案中提出的解决方案那么容易,但我认为实际算法可以更简洁地实现。以下代码首先将有资格享受折扣的组中的商品分批处理。然后,对于每个批次,它都会跳过多达payFor
件商品,并从其余商品中计算出折扣价
// first batch the items in batches eligible for discount (e.g. batches of three in take 3, pay for x)
var batchedItems = BatchItemsEligibleForDiscount(items, minPurchaseQuantity);
var discounts = batchedItems.Select(batch => batch.Skip(payFor))
.SelectMany(batch => batch) // flatten nested IEnumerable to an IEnumerable<Artible>
.Select(article => new Discount() { Value = article.UnitPrice });
BatchItemsEligibleForDiscount
获得有资格享受折扣的批次(即,如果“拿3,付X钱”,则每个都有3件商品。。带有Quantity>1
的文章是“爆炸” ,即,如果数量为3,则会创建3个不同的对象。
IEnumerable<IEnumerable<Article>> BatchItemsEligibleForDiscount(items, minPurchaseQuantity)
{
return items.OrderByDescending(article => article.UnitPrice)
.Select(article => Enumerable.Range(1, article.Quantity).Select(n => new Article() { Quantity = 1, UnitPrice = article.UnitPrice })) // "explode" articles
.SelectMany(item => item) // flatten to an IEnumerable<Article>
.Select((article, index) => new { article, index })
.GroupBy(x => x.index / minPurchaseQuantity)
.Where(group => group.Count() == minPurchaseQuantity) // only take batches elegible for discount
.Select(group => group.Select(x => x.article));
}
请参见this fiddle进行演示。
旧答案
计算折扣要容易得多。您可以计算可享受折扣的捆绑商品数量(如果折扣为3,则支付2和8件商品,那么您将获得两个整体捆绑的商品,每个捆绑3件商品)。通过计算要购买的商品和要支付的商品之间的差,并将其乘以捆绑数和每件商品的价格,可以计算出折扣
var numberOfDiscountableBundles = article.Quantity / amountOfItemsElegibleForDiscount;
var discount = numberOfDiscountableBundles * (amountOfItemsElegibleForDiscount - payFor) * article.UnitPrice;
示例:以3,支付1的价格购买8种商品:
numberOfDiscountableBundles = 8 / 3 = 2 (integer division!)
discount = 2 * (3 - 1) * p = 2 * 2 * p = 4 * p
这是两个打折的捆绑包,每个捆绑三个物品(六个物品)。其中的四项未支付(每捆仅一项),因此总价被打折为单位价格的四倍。
您可以将其封装在方法中
Discount CalculateDiscountForArticle(Article article, int amountOfItemsElegibleForDiscount, int payFor)
{
var numberOfDiscountableBundles = article.Quantity / amountOfItemsElegibleForDiscount;
var discount = numberOfDiscountableBundles * (amountOfItemsElegibleForDiscount - payFor) * article.UnitPrice;
return new Discount
{
Value = discount
};
}
您的原始功能变得简单
var discounts = articlesForPackage.OrderByDescending(a => a.UnitPrice)
.Select(a => CalculateDiscountForArticle(a, amountOfItemsElegibleForDiscount, payFor));
编辑旧答案
如果每个客户和每条商品仅授予一次折扣,则计算会有所不同
double discount = 0;
if(article.Quantity >= amountOfItemsElegibleForDiscount)
{
var discount = (amountOfItemsElegibleForDiscount - payFor) * article.UnitPrice;
}