加入两个列表时如何处理重复键?

时间:2014-01-29 11:27:00

标签: c# linq list join

我是C#的新手。

我有以下结构。

struct Foo
{
    string key;
    Bar values;
}

我有两个相同大小的Foo,L1和L2列表都包含相同的键集。

我必须在L1和L2中合并相应的Foo实例。

Foo Merge(Foo f1, Foo f2)
{
   // merge f1 and f2.
   return result.
}

为了达到这个目的,我写了以下内容。

resultList = L1.Join(L2, f1 => f1.key, f2 => f2.key, (f1, f2) => Merge(f1, f2)
                        ).ToList())

我的问题是我的钥匙不是唯一的。我在L1中有n个具有相同键的元素(比如“key1”)(它们也出现在某个地方的L2中)。因此,上面的连接语句为来自L1的每个“key1”从L2中选择n个匹配条目,并且在结果中我得到n * n个元素,其中键只有“key1”,我只想要n。 (因此,这是那些元素的交叉产品)。

我想使用Join并仍然使用“key1”从L1中选择一个元素并强制Linq使用L2中第一个可用的“未使用”“key1”元素。这可能吗?在这里加入一个坏主意吗?

(另外,我想保留按键的顺序,如在L1中。我试图在连接之前处理所有带有这些键的元素,并从L1和L2中删除这些条目。这扰乱了键的顺序和它看起来很难看。

我正在寻找一种没有任何明确for循环的解决方案。

enter image description here

5 个答案:

答案 0 :(得分:2)

从您的评论到ElectricRouge回答,您可以执行类似

的操作
var z = list1.Join(list2.GroupBy(m => m.Id), 
                   m => m.Id, 
                   g => g.Key, 
                   (l1, l2) => new{l1, l2});

这将为您提供l1中所有键的列表,以及l2中相应的分组键。

不确定它真的可读。

答案 1 :(得分:1)

I need to find the corresponding entries in two lists and do some operation on them. That is my preliminary requirement

为此你可以做这样的事情。

var z=S1.Select(i=>i.Key).Tolist(); //make a list of all keys in S1
List<Foo> result=new List<Foo>();
foreach(var item in z)    // Compare with S2 using keys in z
{
   var x=item.Where(i=>i.Key==item.Key)
   result.Add(x);  
}

这是你在找什么?

答案 2 :(得分:1)

  

我想使用Join并仍然使用“key1”从L1中选择一个元素并强制Linq使用L2中第一个可用的“未使用”“key1”元素。这可能吗?

当组合两个列表中的元素时,您要选择第二个列表中与第一个列表中的元素具有相同键的第一个元素。 (以前,我以不同的方式解释了您的问题,并且在此答案的编辑历史记录中提供了针对此不同问题的解决方案。)

为了快速访问第二个列表中的所需值,创建一个字典,提供从键到第二个列表中所需值的查找:

var dictionary2 = list2
  .GroupBy(foo => foo.Key)
  .ToDictionary(group => group.Key, group => group.First());

使用First表示您想要选择第二个列表中具有相同键的第一个元素的要求。

现在,通过在第一个列表上使用投影来创建合并列表:

var mergedList = list1.Select(
  foo => Merge(
    foo,
    dictionary2[foo.Key]
  )
);

当您使用foreach来迭代mergedListToList()时,系统会计算出所需的结果。

答案 3 :(得分:0)

您可以使用Union删除重复的密钥。 http://msdn.microsoft.com/en-us/library/bb341731.aspx

上的文档
List<int> list1 = new List<int> { 1, 12, 12, 5};
List<int> list2 = new List<int> { 12, 5, 7, 9, 1 };
List<int> ulist = list1.Union(list2).ToList();

示例摘自:how to merge 2 List<T> with removing duplicate values in C#

或者您可以使用Concat合并不同类型的列表(保留所有键)。 请参阅她的文档:http://msdn.microsoft.com/en-us/library/bb302894(v=vs.110).aspx

var MyCombinedList = Collection1.Concat(Collection2)
                                .Concat(Collection3)
                                .ToList();

取自同一问题的示例:Merge two (or more) lists into one, in C# .NET

答案 4 :(得分:0)

最后我调整了Raphaël的答案如下。

public class FooComparer : IEqualityComparer<Foo>
{
      public bool Equals(Foo o1, Foo o2)
      {
          return o1.key == o2.key;
      }

      public int GetHashCode(Foo obj)
      {
          return obj.key.GetHashCode();
      }
}


resultList = L1.Join(L2.Select(m => m).Distinct(new FooComparer()).ToList(), f1 => f1.key, f2 => f2.key, (f1, f2) => Merge(f1, f2)
                        ).ToList());

简短说明:

L2.Select(m => m).Distinct(new FooComparer()).ToList()

通过从L2中删除重复键来创建新列表。使用此新列表加入L1以获得所需的结果。