C# 如何使用LINQ将共享1个属性的两个列表合并为第三个列表?
我希望创建以下类的列表(列表): 此列表应包含另外两个列表的信息:一个C# 如何使用LINQ将共享1个属性的两个列表合并为第三个列表?,c#,linq,list,C#,Linq,List,我希望创建以下类的列表(列表): 此列表应包含另外两个列表的信息:一个列表和一个列表。两个类都具有以下形状: public class Contact { public DateTime? RegisterDate { get; set; } public string Name { get; set; } } public class Purchase { public DateTime? PurchaseDate { get; set; } public i
列表
和一个列表
。两个类都具有以下形状:
public class Contact
{
public DateTime? RegisterDate { get; set; }
public string Name { get; set; }
}
public class Purchase
{
public DateTime? PurchaseDate { get; set; }
public int PurchaseID {get;set;}
public int Import { get; set; }
}
我们的想法是,列表应该是每天的注册用户数量、购买量以及这些购买的总进口量。所以,从本质上说,双方只是共享日期
但是,我不能用一个好的LINQ表达式来创建列表。我考虑的一个解决方案是检索两个列表中所有不同的日期,然后迭代它们以检索我想要的信息,但我认为这种方法相当“丑陋”。有什么方法可以轻松地完成我想做的事情吗
编辑:我想要的示例如下:
Contacts
--------
Name RegisteredDate
David 10/10/2013
Paul 09/10/2013
Gina 10/10/2013
Roger 09/10/2013
Rose 05/10/2013
Jean 07/10/2013
Mark 04/10/2013
Lisa 04/10/2013
Purchases
-----------
ID PurchaseDate Import
1 10/10/2013 10
2 10/10/2013 10
3 10/10/2013 20
4 04/10/2013 15
5 04/10/2013 15
6 07/10/2013 20
7 07/10/2013 2
8 07/10/2013 2
Expected result
----------------
Date RegisteredUsers Purchases Import
04/10/2013 2 2 30
05/10/2013 1 0 0
07/10/2013 1 3 24
09/10/2013 2 0 0
10/10/2013 2 3 40
亲切问候因此这里有几个单独的任务。您要做的第一件事是按注册日期将联系人分组。接下来,您将根据日期将该结果连接到Purchases表,在两个不同的列上聚合count/sums。LINQ对这两个操作都有一个方法:
var query = from contact in contacts
group contact by contact.RegisterDate into contactGroup
join purchase in purchases
on contactGroup.Key equals purchase.PurchaseDate into purchaseGroup
select new StatusData
{
Date = contactGroup.Key,
RegisteredUsers = contactGroup.Count(),
Orders = purchaseGroup.Count(),
Import = purchaseGroup.Sum(p => p.Import),
};
var contacts=newlist();
var购买=新列表();
变量日期=联系人。选择(x=>x.RegisterDate.Value)
.Concat(purchases.Select(x=>x.PurchaseDate.Value))
.Distinct();
var数据=日期中的起始日期
在日期等于c.RegisterDate.Value的联系人中加入c
在购买日加入p等于p.PurchaseDate.Value
选择新状态数据{
日期=日期,
RegisteredUsers=registered.Count(),
订单=采购。计数(),
Import=purchases.Sum(x=>x.Import)
};
当至少进行了一次注册或一次购买时,它将返回所有天的
StatusData
。这实际上是两个单独的查询,其结果在最后合并
var contact = from c in Contact
group c by c.RegisterDate into c
select new StatusData
{
Date = c.Key,
RegisteredUsers = c.Count(),
Orders = 0,
Import = 0,
};
var purchases = from p in Purchases
group p by p.PurchaseDate into p
select new StatusData
{
Date = p.Key,
RegisteredUsers = 0,
Orders = p.Count(),
Import = p.Sum(x => x.Import),
};
var final = from x in contact.Concat(purchases)
group x by x.Date into x
select new StatusData
{
Date = x.Key,
RegisteredUsers = x.Sum(y => y.RegisteredUsers),
Orders = x.Sum(y => y.Orders),
Import = x.Sum(y => y.Import),
};
一个简单的例子会有很大的帮助,不清楚你想要什么。你能提供测试数据和期望的结果吗?我添加了一个例子来说明我想要得到什么。我很抱歉。在给定日期有购买时,它不会返回记录,但没有用户注册。这种方法,以及@MarcinJuraszek的方法,非常容易理解和实现。谢谢你们:)你们认为可以使用.Aggregate()来减少枚举数吗(可能是由于.Sum())?这种方法很有趣,因为它使我能够考虑一种不需要任何注册或购买就可以包含方法的方法。谢谢大家!@DavidJiménezMartínez是的,用这种方法很容易做到。只需更改
日期
定义,以包含您感兴趣的两个日期之间的所有日期。我想我必须修改linq表达式,以允许在没有任何注册或购买的情况下对日期进行左外联接。我认为您不需要任何更改即可获得该定义。
var contacts = new List<Contact>();
var purchases = new List<Purchase>();
var dates = contacts.Select(x => x.RegisterDate.Value)
.Concat(purchases.Select(x => x.PurchaseDate.Value))
.Distinct();
var data = from date in dates
join c in contacts on date equals c.RegisterDate.Value into registered
join p in purchases on date equals p.PurchaseDate.Value into purchased
select new StatusData {
Date = date,
RegisteredUsers = registered.Count(),
Orders = purchases.Count(),
Import = purchases.Sum(x => x.Import)
};
var contact = from c in Contact
group c by c.RegisterDate into c
select new StatusData
{
Date = c.Key,
RegisteredUsers = c.Count(),
Orders = 0,
Import = 0,
};
var purchases = from p in Purchases
group p by p.PurchaseDate into p
select new StatusData
{
Date = p.Key,
RegisteredUsers = 0,
Orders = p.Count(),
Import = p.Sum(x => x.Import),
};
var final = from x in contact.Concat(purchases)
group x by x.Date into x
select new StatusData
{
Date = x.Key,
RegisteredUsers = x.Sum(y => y.RegisteredUsers),
Orders = x.Sum(y => y.Orders),
Import = x.Sum(y => y.Import),
};