如何合并两个列表

时间:2015-09-02 08:28:04

标签: c# linq

我想合并以下类的两个列表

public class ContactsByUser
{
    public int UserId { get; set; }
    public string Username { get; set; }
    public int CountContacts { get; set; }
    public int CountBehaviorInterview { get; set; }

    public override bool Equals(object obj)
    {
        return this.UserId == ((ContactsByUser)obj).UserId;
    }

    public override int GetHashCode()
    {
        return UserId.GetHashCode();
    }
}

现在我有2个包含以下内容的列表

    List<ContactsByUser> contacts = new List<ContactsByUser>();
contacts.Add( new ContactsByUser { UserId = 1, Username = user1, CountContacts = 42, CountBehaviorInterview = 0});
contacts.Add( new ContactsByUser { UserId = 2, Username = user2, CountContacts = 25, CountBehaviorInterview = 0});
contacts.Add( new ContactsByUser { UserId = 3, Username = user3, CountContacts = 7, CountBehaviorInterview = 0});
contacts.Add( new ContactsByUser { UserId = 4, Username = user4, CountContacts = 10, CountBehaviorInterview = 0});
contacts.Add( new ContactsByUser { UserId = 5, Username = user5, CountContacts = 23, CountBehaviorInterview = 0});
contacts.Add( new ContactsByUser { UserId = 6, Username = user6, CountContacts = 60, CountBehaviorInterview = 0});
contacts.Add( new ContactsByUser { UserId = 7, Username = user7, CountContacts = 3, CountBehaviorInterview = 0});

List<ContactsByUser> interviews = new List<ContactsByUser>();
interviews .Add( new ContactsByUser { UserId = 1, Username = user1, CountContacts = 0, CountBehaviorInterview = 33});
interviews .Add( new ContactsByUser { UserId = 2, Username = user2, CountContacts = 0, CountBehaviorInterview = 21});
interviews .Add( new ContactsByUser { UserId = 3, Username = user3, CountContacts = 0, CountBehaviorInterview = 8});
interviews .Add( new ContactsByUser { UserId = 4, Username = user4, CountContacts = 0, CountBehaviorInterview = 17});

合并这两个列表时我想要的是以下结果

{ UserId = 1, Username = user1, CountContacts = 42, CountBehaviorInterview = 33});
{ UserId = 2, Username = user2, CountContacts = 25, CountBehaviorInterview = 21});
{ UserId = 3, Username = user3, CountContacts = 7, CountBehaviorInterview = 8});
{ UserId = 4, Username = user4, CountContacts = 10, CountBehaviorInterview = 17});
{ UserId = 5, Username = user5, CountContacts = 23, CountBehaviorInterview = 0});
{ UserId = 6, Username = user6, CountContacts = 60, CountBehaviorInterview = 0});
{ UserId = 7, Username = user7, CountContacts = 3, CountBehaviorInterview = 0});

在第一个列表中,CountBehaviorInterview属性将始终为0,而​​在第二个列表上,CountContacts将始终为0.

我尝试过使用union,但它只是返回一个包含2个列表的列表。有没有办法以我需要的方式合并这些?

3 个答案:

答案 0 :(得分:0)

如果您可以更改contacts列表中的对象,则可以使用简单的Joinforeach

foreach(var joined in contacts.Join(interviews, 
                                    o => o.UserId, 
                                    i => i.UserId, 
                                    (originalContact, i) => new {originalContact, i.CountBehaviorInterview}))
{
    joined.originalContact.CountBehaviorInterview = joined.CountBehaviorInterview;
}

如果你想创建ContactsByUser的新实例,那么你正在寻找一个左外连接,如下所示:

var result = from i in contacts
             join o in interviews on i.UserId equals o.UserId into j
             from o in j.DefaultIfEmpty()
             select  new ContactsByUser
                     {
                         UserId = i.UserId, 
                         Username = i.Username, 
                         CountContacts = i.CountContacts, 
                         CountBehaviorInterview = j.Any() ? j.Single().CountBehaviorInterview : 0
                      };

或者,使用不同的方法(可能更慢,取决于您的数据,但可能无关紧要):

var result = from i in contacts
             from o in interviews.Where(k => k.UserId == i.UserId).DefaultIfEmpty()
             select  new ContactsByUser
                     {
                         UserId = i.UserId, 
                         Username = i.Username, 
                         CountContacts = i.CountContacts, 
                         CountBehaviorInterview = o != null ? o.CountBehaviorInterview : 0
                      };

答案 1 :(得分:0)

如果您不想创建ContactsByUser的新实例,您可以:

var interviewsByUserId = interviews.ToDictionary(i=>i.UserId, i=>i);
contacts.ForEach(c => 
{
    ContactsByUser interview;
    if (!interviewsByUserId.TryGetValue(c.UserId, out interview))
        return;

    c.CountBehaviorInterview = interview.CountBehaviorInterview;
});

答案 2 :(得分:0)

以下我将如何解决这个问题:

var lookup = interviews.ToLookup(i => i.UserId, i => i.CountBehaviorInterview);

var result =
    contacts
        .Select(c => new ContactsByUser()
        {
            UserId = c.UserId,
            Username = c.Username,
            CountContacts = c.CountContacts,
            CountBehaviorInterview = lookup[c.UserId].Sum(),
        })
        .ToList();

这可以很好地处理interviews列表中的遗漏和重复项目。

我得到了这个结果:

result