Linq查询合并2个列表 [英] Linq Query To Combine 2 Lists

查看:75
本文介绍了Linq查询合并2个列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有2个列表,我需要合并A和B中的联接值,但还包括A和B中与联接不匹配的值.

  class TypeA{公共字符串Key {get;放;}public int ValueA {get;放;}}B类{公共字符串Key {get;放;}public int ValueB {get;放;}}AB类{公共字符串Key {get;放;}public int ValueA {get;放;}public int ValueB {get;放;}}var listA = new List< TypeA>{新的TypeA {键=一个",值= 1},new TypeA { Key = "two", Value = 2 },};var listB = new List< TypeB>{新的TypeB {键=两个",值= 2},新的TypeB {键=三",值= 3},}; 

我希望这些列表的总和等于:

  var listAB = new List< TypeAB>{新的TypeAB {键=一个",ValueA = 1,ValueB = null},new TypeAB { Key = "two", ValueA = 2, ValueB = 2 },新的TypeAB {键=三",ValueA =空,ValueB = 3},}; 

将执行此操作的Linq语句是什么?我一直在玩,不能完全到达那里.我可以通过在A到B上进行左外部联接,并在B到A上进行左外部联接进行并集来达到目标​​,但是我得到重复的Intersection值.

更新

这是我根据乔治的回答所做的事情:

  var join =(来自listA中的加入listB中的b在a.Key等于b.Key进入listBJoin从listBJoin.DefaultIfEmpty(new TypeB())中的b开始选择新的TypeAB{键= a.键,ValueA = a.ValueA,ValueB = b.ValueB,} .Union(从listB中的b其中!listA.Any(d => d.Key == b.Key)选择新的TypeAB{键= b.键,ValueB = b.ValueB,}).ToList(); 

解决方案

编辑:已修复.这很草率,但应该可以.

  listA//以lisA开头.Where(a =>!listB.Any(b => a.Key == b.Key))//删除在listB中重复的任何内容.Select(a => new TypeAB(){Key = a.Key,ValueA = a.Value})//将每个A映射到AB.联盟(listB.Select(b => {var relativeA = listA.FirstOrDefault(a => a.Key == b.Key);//是否有一个对应的?返回新的TypeAB(){Key = b.Key,ValueB = b.Value,//值B很简单值A =对应A!=空?(int?)correspondingA.Value:null//如果A比映射其值};})) 

顺便说一句,如果您将此操作用作某种域操作,则TypeA和TypeB可能应该基于某种AorBIsAConceptThatHasMeaningInTheDomain基类.每当您发现自己合并列表时,这只是一条一般规则.如果不存在这样的概念,那么您可能不需要合并列表.

另一方面,如果您在映射过程中执行此操作(例如将域对象映射到UI),则可以使用匿名类型而不是TypeAB类来简化代码.(或者可能不是,这取决于个人喜好)

编辑编辑这是一个使用散列在智力上更有趣的答案

  var listAB = listA.Cast< object>().Union(listB.Cast< object>()).ToLookup(x => x是TypeA?(x为TypeA).Key:(x作为TypeB).Key).Select(kv => {var a = kv.FirstOrDefault(x => x是TypeA)作为TypeA;var b = kv.FirstOrDefault(x => x is TypeB)作为TypeB;返回新的TypeAB(){键= kv.Key,ValueA = a!=空值?(int?)a.Value:null,ValueB = b!= null?(int?)b.Value:空};}).ToList(); 

I have 2 lists and I need to combine the joining values from A and B, but also include the values from A and B that don't match the join.

class TypeA
{
    public string Key { get; set; }
    public int ValueA { get; set; }
}

class TypeB
{
    public string Key { get; set; }
    public int ValueB { get; set; }
}

class TypeAB
{
    public string Key { get; set; }
    public int ValueA { get; set; }
    public int ValueB { get; set; }
}

var listA = new List<TypeA>
{
    new TypeA { Key = "one", Value = 1 },
    new TypeA { Key = "two", Value = 2 },
};

var listB = new List<TypeB>
{
    new TypeB { Key = "two", Value = 2 },
    new TypeB { Key = "three", Value = 3 },
};

I want these lists combined to equal this:

var listAB = new List<TypeAB>
{
    new TypeAB { Key = "one", ValueA = 1, ValueB = null },
    new TypeAB { Key = "two", ValueA = 2, ValueB = 2 },
    new TypeAB { Key = "three", ValueA = null, ValueB = 3 },
};

What is a Linq statement that will do this? I've been playing around and can't quite get there. I can get almost there by doing a left outer join on A to B and Union that to a left outer join on B to A, but I get duplicate Intersection values.

Update

Here is what I did based on George's answer:

var joined =
    ( from a in listA
      join b in listB
        on a.Key equals b.Key
        into listBJoin
      from b in listBJoin.DefaultIfEmpty( new TypeB() )
      select new TypeAB
      {
        Key = a.Key,
        ValueA = a.ValueA,
        ValueB = b.ValueB,
      } ).Union(
        from b in listB
        where !listA.Any( d => d.Key == b.Key )
        select new TypeAB
        {
            Key = b.Key,
            ValueB = b.ValueB,
        }
        ).ToList();

解决方案

Edit: Fixed up. This is sloppy but it should work.

    listA  //Start with lisA
.Where(a=>!listB.Any(b=>a.Key == b.Key))  // Remove any that are duplicated in listB
.Select(a => new TypeAB() { Key=a.Key, ValueA=a.Value})  // Map each A to an AB
.Union(
  listB.Select(b => {
      var correspondingA = listA.FirstOrDefault(a => a.Key == b.Key);  //Is there an a that corresponds?
    return new TypeAB() { Key=b.Key, 
      ValueB=b.Value,  //Value B is easy
      ValueA= correspondingA!=null ? (int?)correspondingA.Value : null  //If there is an A than map its value
    };
  })
)

As an aside, if you're using this as some sort of domain operation, TypeA and TypeB should probably be based on some sort AorBIsAConceptThatHasMeaningInTheDomain base class. That's just a general rule whenever you find yourself combining lists. If no such concept exists, then you probably don't need to be combining the lists.

On the other hand, if you're doing this as part of a mapping - such as mapping domain objects to UI - you might be able to simplify your code somewhat by using anonymous types instead of a TypeAB class. (Or maybe not, this one is up to personal preference)

Edit Edit Here's a slightly more intellectually interesting answer using hashes

        var listAB = listA.Cast<object>().Union(listB.Cast<object>()).ToLookup(x => x is TypeA ? (x as TypeA).Key : (x as TypeB).Key)
                .Select(kv => {
                    var a = kv.FirstOrDefault(x => x is TypeA) as TypeA;
                    var b = kv.FirstOrDefault(x => x is TypeB) as TypeB;
                    return new TypeAB() {
                        Key = kv.Key,
                        ValueA = a != null ? (int?)a.Value : null,
                        ValueB = b != null ? (int?)b.Value : null
                    };
                }).ToList();

这篇关于Linq查询合并2个列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆