C# 使用LINQ查找两个列表中项目的复杂组合
这个问题与我先前的一个问题非常相似,只是有一些进一步的曲折 我有一个C# 使用LINQ查找两个列表中项目的复杂组合,c#,.net,vb.net,linq,C#,.net,Vb.net,Linq,这个问题与我先前的一个问题非常相似,只是有一些进一步的曲折 我有一个CartItems列表,可以根据DiscountItems列表中指定的项目获得折扣。我需要能够取出购物车中可以获得折扣的项目,并应用折扣项目中指定的适当折扣。折扣仅适用于存在的每个组合。以下是两个列表在应用折扣之前的外观: BEFORE DISCOUNT: CartItems DiscountItems =====================
CartItem
s列表,可以根据DiscountItem
s列表中指定的项目获得折扣。我需要能够取出购物车中可以获得折扣的项目,并应用折扣项目中指定的适当折扣。折扣仅适用于存在的每个组合。以下是两个列表在应用折扣之前的外观:
BEFORE DISCOUNT:
CartItems DiscountItems
============================== ===========================
SKU Qty DiscountApplied SKU DiscountAmount
============================== ===========================
Ham 2 $0.00 Ham $0.33
Bacon 1 $0.00 Bacon $2.00
Ham 1 $0.00
Bacon 2 $0.00
Cheese 1 $0.00
Bacon 1 $0.00
After 1st Discount is applied:
CartItems DiscountItems
============================== ===========================
SKU Qty DiscountApplied SKU DiscountAmount
============================== ===========================
Ham 2 $0.33 Ham $0.33
Bacon 1 $2.00 Bacon $2.00
Ham 1 $0.00
Bacon 2 $0.00
Cheese 1 $0.00
Bacon 1 $0.00
After 2nd Discount is applied:
CartItems DiscountItems
============================== ===========================
SKU Qty DiscountApplied SKU DiscountAmount
============================== ===========================
Ham 2 $0.66 Ham $0.33
Bacon 1 $2.00 Bacon $2.00
Ham 1 $0.00
Bacon 2 $2.00
Cheese 1 $0.00
Bacon 1 $0.00
After 3rd Discount is applied:
CartItems DiscountItems
============================== ===========================
SKU Qty DiscountApplied SKU DiscountAmount
============================== ===========================
Ham 2 $0.66 Ham $0.33
Bacon 1 $2.00 Bacon $2.00
Ham 1 $0.33
Bacon 2 $4.00
Cheese 1 $0.00
Bacon 1 $0.00
最后,除了奶酪和额外的熏肉,所有的东西都打折了。奶酪不打折,因为它不是列表中的打折商品。额外的培根不会得到折扣,因为它没有相应的火腿项目来获得折扣组合。一共有3个火腿和4个香肠,所以其中一个香肠不会打折
我想我应该能够使用LINQ解决这个问题,因为它涉及枚举2个独立的列表,但我想不出我会使用什么LINQ方法来实现这一点。LINQ查询的最终结果应该是已应用折扣的CartItem
s的集合。好的,只是为了好玩,这里有一种LINQ解决方案
它的可读性和效率可能远不及等价的迭代代码,但它是有效的
var discountedCart = CartItems.Select(c => c);
var combinations = DiscountItems.Any()
? DiscountItems.GroupJoin(CartItems, d => d.SKU, c => c.SKU, (d, g) => g.Sum(c => c.Qty)).Min()
: 0;
if (combinations > 0)
{
var map = DiscountItems.ToDictionary(d => d.SKU, d => combinations);
discountedCart = CartItems.Select(c =>
{
int mul;
map.TryGetValue(c.SKU, out mul);
if (mul < 1)
return c;
decimal amt = DiscountItems.Single(d => d.SKU == c.SKU).DiscountAmount;
int qty = Math.Min(mul, c.Qty);
map[c.SKU] = mul - qty;
return new CartItem { SKU = c.SKU, Qty = c.Qty, DiscountApplied = amt * qty };
});
}
foreach (CartItem item in discountedCart)
{
Console.WriteLine("SKU={0} Qty={1} DiscountApplied={2}", item.SKU, item.Qty, item.DiscountApplied);
}
var discountedCart=CartItems.Select(c=>c);
var组合=折扣项。任何()
? 折扣项.GroupJoin(CartItems,d=>d.SKU,c=>c.SKU,(d,g)=>g.Sum(c=>c.Qty)).Min()
: 0;
如果(组合>0)
{
var map=折扣项目。ToDictionary(d=>d.SKU,d=>组合);
折扣部分=购物车项目。选择(c=>
{
int mul;
映射TryGetValue(c.SKU,out mul);
如果(mul<1)
返回c;
十进制金额=折扣单(d=>d.SKU==c.SKU)。折扣金额;
整数数量=数学最小值(多个,c数量);
映射[c.SKU]=多个-数量;
返回新CartItem{SKU=c.SKU,Qty=c.Qty,折扣应用=amt*Qty};
});
}
foreach(折扣部分的CartItem项目)
{
Console.WriteLine(“SKU={0}数量={1}折扣应用={2}”,item.SKU,item.Qty,item.折扣应用);
}
(我怀疑,如果您想要一个没有副作用的LINQ查询,那么您可以将其全部封装在一个调用中,但这将需要进一步的丑陋和低效。)要获得您想要的准确结果有点困难。您可能需要存储中间结果-因此需要引入一个新类。这是一个挑战,所以我做了如下-它似乎工作
class Program {
public class CartItem {
public string sku { get; set; }
public int qty {get;set;}
public decimal DiscountApplied { get; set; }
public CartItem(string sku,int qty,decimal DiscountApplied) {
this.sku=sku;
this.qty=qty;
this.DiscountApplied=DiscountApplied;
}
}
public class DiscountItem{
public string sku {get;set;}
public decimal DiscountAmount {get; set;}
}
static List<CartItem> carts=new List<CartItem>(){
new CartItem("Ham",2,0.0m ),
new CartItem("Bacon",1,0.00m ),
new CartItem("Ham",1,0.00m ),
new CartItem("Bacon",2 ,0.00m),
new CartItem("Cheese",1,0.00m),
new CartItem("Bacon" , 1 , 0.00m )};
static List<DiscountItem> discounts=new List<DiscountItem>() {
new DiscountItem(){ sku="Ham", DiscountAmount=0.33m},
new DiscountItem(){sku="Bacon",DiscountAmount=2.0m}};
class cartsPlus
{
public CartItem Cart { get; set; }
public int AppliedCount { get; set; }
}
public static void Main(string[] args){
int num = (from ca in discounts
join cart in carts on ca.sku equals cart.sku
group cart by ca.sku into g
select new { Sku = g.Key, Num = g.Sum(x => x.qty) }).Min(x => x.Num);
var cartsplus = carts.Select(x => new cartsPlus { Cart = x, AppliedCount = 0 }).ToList();
discounts.SelectMany(x => Enumerable.Range(1, num).Select(y => x)).ToList().ForEach(x=>{cartsPlus c=cartsplus.
First(z=> z.Cart.sku==x.sku&&z.AppliedCount<z.Cart.qty);c.AppliedCount++;c.Cart.DiscountApplied+=x.DiscountAmount;});
foreach (CartItem c in carts)
Console.WriteLine("{0} {1} {2}", c.sku,c.qty, c.DiscountApplied);
}
};
类程序{
公共类商品{
公共字符串sku{get;set;}
公共整数数量{get;set;}
公开十进制折扣应用{get;set;}
公共CartItem(字符串sku、整数数量、小数折扣){
this.sku=sku;
该数量=数量;
this.DiscountApplied=DiscountApplied;
}
}
公开课折扣{
公共字符串sku{get;set;}
公共十进制折扣挂载{get;set;}
}
静态列表推车=新列表(){
新卡塔姆项目(2.0米),
新项目(“培根”,1,0.00m),
新卡塔姆项目(“1,0.00m”),
新项目(“培根”,2,0.00m),
新项目(“奶酪”,1,0.00m),
新项目(“培根”,1,0.00m)};
静态列表折扣=新列表(){
新折扣项目(){sku=“Ham”,折扣量=0.33m},
新折扣项目(){sku=“Bacon”,折扣额=2.0m};
cartsPlus类
{
公共CartItem购物车{get;set;}
public int AppliedCount{get;set;}
}
公共静态void Main(字符串[]args){
int num=(来自ca的折扣)
将购物车加入ca.sku上的购物车等于cart.sku
按ca.sku将购物车分组为g
选择new{Sku=g.Key,Num=g.Sum(x=>x.qty)}).Min(x=>x.Num);
var cartsplus=carts.Select(x=>newcartsplus{Cart=x,AppliedCount=0}).ToList();
折扣.SelectMany(x=>Enumerable.Range(1,num).Select(y=>x)).ToList().ForEach(x=>{cartsPlus c=cartsPlus。
首先(z=>z.Cart.sku==x.sku&&z.AppliedCount编辑:我刚刚意识到这个问题有多老了
我个人会使用以下内容,因为它对我来说是最可读的。它没有使用很多Linq,但我相信它是最不复杂的答案
// For each discount that can be applied
foreach(var discount = DiscountedItems.Where(c => CartItems.Any(d => d.SKU == c.SKU)))
{
var discountLimit = 3; // how many items are allowed to have a discount.
foreach(var item in CartItems.Where(d => d.SKU == item.SKU))
{
if(discountLimit < item.Quantity)
{
// update the discount applied
item.DiscountApplied = discountLimit * discount.DiscountAmount;
discountLimit = 0; // causes the rest of the items to not get a discount
}
else
{
// update the discount applied
item.DiscountApplied = item.Qty * discount.DiscountAmount;
discountLimit -= item.Qty;
}
}
}
//对于可以应用的每个折扣
foreach(var折扣=折扣数据项,其中(c=>CartItems.Any(d=>d.SKU==c.SKU)))
{
var discountLimit=3;//允许折扣的项目数。
foreach(CartItems.Where(d=>d.SKU==item.SKU)中的var项)
{
if(折扣限额<项目数量)
{
//更新应用的折扣
item.DiscountApplied=折扣限额*折扣.DiscountAmount;
折扣限制=0;//导致其他项目无法获得折扣
}
其他的
{
//更新应用的折扣
item.DiscountApplied=item.Qty*discount.DiscountAmount;
折扣限额-=物料数量;
}
}
}
如果您有MoreLinq或LinqKit,还可以执行以下操作:
// For each discount that can be applied
DiscountedItems.Where(c => CartItems.Any(d => d.SKU == c.SKU)).foreach(discount =>
{
var discountLimit = 3; // how many items are allowed to have a discount.
CartItems.Where(d => d.SKU == item.SKU).foreach(item =>
{
if(discountLimit < item.Quantity)
{
// update the discount applied
item.DiscountApplied = discountLimit * discount.DiscountAmount;
discountLimit = 0; // causes the rest of the items to not get a discount
}
else
{
// update the discount applied
item.DiscountApplied = item.Qty * discount.DiscountAmount;
discountLimit -= item.Qty;
}
});
});
//对于可以应用的每个折扣
折扣数据项。其中(c=>CartItems.Any(d=>d.SKU==c.SKU)).foreach(折扣=>
{
var discountLimit=3;//允许折扣的项目数。
CartItems.Where(d=>d.SKU==item.SKU).foreach(item=>
{
if(折扣限额<项目数量)
{
//更新应用的折扣
item.DiscountApplied=折扣限额*折扣.DiscountAmount;
折扣限制=0;//导致其他项目无法获得折扣
}
其他的
{
//更新应用的折扣
item.DiscountApplied=item.Q
// For each discount that can be applied
DiscountedItems.Where(c => CartItems.Any(d => d.SKU == c.SKU)).foreach(discount =>
{
var discountLimit = 3; // how many items are allowed to have a discount.
CartItems.Where(d => d.SKU == item.SKU).foreach(item =>
{
if(discountLimit < item.Quantity)
{
// update the discount applied
item.DiscountApplied = discountLimit * discount.DiscountAmount;
discountLimit = 0; // causes the rest of the items to not get a discount
}
else
{
// update the discount applied
item.DiscountApplied = item.Qty * discount.DiscountAmount;
discountLimit -= item.Qty;
}
});
});