2013-01-16 26 views
5

我有两个查询,每个查询返回一个对象列表。如何合并给定属性上的两个列表

List<A> list1 = (....query...) 
List<A> list2 = (....query...) 

“A”是对象模型。

这两个查询都返回几乎相同的对象,但设置了不同的属性。

我想删除重复的将它们合并为基于对象A的属性

基本上是这样一个列表:

List<A> finalLis = list1 join list2 on elemList1.somePropID == elemList2.somePropID 

在简单的C#的风格会是这样的:

foreach(elem1 : list1) { 
    foreach(elem2: list1) { 
     if(elem1.someID == elem2.someID) { 
      elem1.someProp = elem2.someProp 
      elem1.otherProp = elem2.otherProp 
     } 
    } 
} 

我不想这样做,因为我确信linq中有更优雅的方式。

如果您有任何建议,请让我知道。

+0

你想有从第二收集,不第一个集合中匹配的任何项目ID,在结果集中的项目? – mipe34

+0

否....第一个列表中的元素与第二个列表中的元素几乎相同。理念是在第一个列表中没有设置一些属性,但是这些值可以在对应的对象中找到。最终列表是第一个列表,但所有属性都设置为 – cmg

回答

1

的LINQ可以帮助您选择,但不与更新。所以你不会摆脱foreach声明。所以,你的任务可能与LINQ这样写:

//the query is like LEFT JOIN in SQL 
var query = from x in list1 
      join y in list2 on x.IDItem equals y.IDItem 
      into z 
      from q in z.DefaultIfEmpty() 
      select new {IOne = x, ITwo = q}; 
foreach (var pair in query) 
{ 
    if (pair.ITwo != null) // && pair.IOne.OneProperty != null 
     pair.IOne.OneProperty = pair.ITwo.TwoProperty; 
} 

var resultList = query.Select(x => x.IOne).ToList(); 

您可以检查结果here

0

试试这个:

List<A> list = (from e1 in list1 
      join e2 in list2 
      on e1.ID equals e2.ID 
      select new A 
      { 
       ID = l2.ID, 
       someProp1 = l2.someProp1, 
       someProp2 = l2.someProp2 
      }).ToList(); 

那么你将与所有元素的第三个列表。

此链接可能帮助:LINQ Join 2 List<T>s

+1

它不包括每个列表中唯一的对象(具有唯一标识)。它也会创建新的对象而不是更新现有的。 –

+0

但他说差异是一些属性没有设置为list1并设置为list2。而代码示例的编写方式我想他想要第三个列表。 –

0

的LINQ是查询,不更新。您可以简化连接,但仍然需要循环才能执行更新。

喜欢的东西:

List<A> finalList = 
    from item1 in list1 
    join item2 in list2 on item1.somePropID equals item2.somePropID 
    select new{Item1 = item1, Item2 = item2}; 

foreach(var item in finalList) 
{ 
    item.Item2.someProp1 = item.Item1.someProp1; 
    item.Item2.someProp2 = item.Item1.someProp2; 
} 
+1

同样的事情 - 最终列表中没有加入ID。 –

+0

好的我没有看到解释的评论。 –

0

想要使用LINQ是正确的。

这里的答案都等同于给定的C#代码片段,除此之外片段效率非常低并且会导致list1.Length * list2.Length操作。

使用LINQ连接更加高效,并且大致产生了list1.Length + list2.Length操作。

这是因为该ID的连接将使用字典

// create a dict so that you can lookup things in item1 based on id 
var list1IdToADict = list1.ToDictionary(a => a.id); 

//filter out things not in both lists (join on there id) 
var joinedList2 = list2.Where(a => list1IdToADict.ContainsKey(a.id)); 

其他答案做这样的事情更elagant,但如果你想要做这种方式,你可以用

foreach(var a in joinedList2){ 
    a.someProp = list1IdToADict[a.id].someProp; 
    a.otherProp = list1IdToADict[a.id].otherProp; 
} 
完成
0

任何有关List<T>的解决方案都将在N * Log(n)处执行,因为这些列表需要进行排序。

在您的模型上实现相等成员,并改为使用HashSet<T>

这在复杂性和分配上都是最佳的。

var set1 = new HashSet<Model> 
{ 
    new Model(0, "000"), 
    new Model(2, "222"), 
    new Model(4, "444"), 
}; 

var set2 = new HashSet<Model> 
{ 
    new Model(1, "111"), 
    new Model(2, "2222"), 
    new Model(3, "333"), 
}; 

set1.ExceptWith(set2); 
set1.UnionWith(set2); 

要添加,使用覆盖集作为结果集会更快。

set2.UnionWith(set1); 

Model上述样本中:

class Model 
{ 
    public readonly int Id; 
    public string Data; 

    public Model(int id, string data) 
    { 
     Id = id; 
     Data = data; 
    } 

    public override int GetHashCode() 
    { 
     return Id; 
    } 

    protected bool Equals(Model other) 
    { 
     return Id == other.Id; 
    } 

    public override bool Equals(object obj) 
    { 
     if (ReferenceEquals(null, obj)) return false; 
     if (ReferenceEquals(this, obj)) return true; 
     return obj.GetType() == GetType() && Equals((Model) obj); 
    } 
}