2009-08-21 266 views
0

我使用LINQ从存储过程调用中检索到的对象集合中构建对象的树形结构。Linq将元素从一个集合中移除到另一个集合中

我想知道,如果
一)有什么办法可以去除从一个集合的元素到一个新的集合
b)如居然有任何一点性能明智的在做这个

我的代码看起来是像这样:

class MyEntity 
{ 
    int ID { get; set; } 
    int? ParentID { get; set; } 
    string Name { get; set; } 
    List<MyEntity> children = new List<MyEntity>(); 
    List<MyEntity> Children { get { return children; } } 
} 

List<MyEntity> initialCollection = //get stuff from DB 

List<MyEntity> rootElements = (from e in initialCollection 
           where e.ParentID == null 
           select e).ToList(); 

List<MyEntity> childElements = (from e in initialCollection 
           where e.ParentID != null 
           select e).ToList(); 

foreach(MyElement e in rootElements) 
    e.Children.AddRange((from c in childElements 
         where c.ParentID == e.ID 
         select c).ToList()); 
//do some more recursion 

所以基本上;有没有办法做选择语句,我真的从initialCollection删除元素,因为我选择它们。这个想法是在递归构建我的树时减少搜索元素的数量。这样做实际上是否会有任何好处,或者是从一个集合中删除元素并添加到另一个集合的开销太大?

回答

3

一个更好的想法是创建一个查询:

var childElements = initialCollection.Where(e => e.ParentID != null) 
            .ToLookup(e => e.ParentID); 

foreach (MyElement e in rootElements) 
{ 
    if (childElements.Contains(e.ID)) 
    { 
     e.Children.AddRange(childElements[e.ID]); 
    } 
} 

的查找是有点像Dictionary<TKey, IEnumerable<TValue>> - 所以基本上你的工作哪些孩子属于哪一方,然后加入他们都在

认为如果您有任何根元素没有孩子,则需要调用Contains - 我希望索引器在指定键不存在的情况下抛出异常。文档虽然不是很清楚 - 它可能会返回一个空序列。

+0

辉煌,非常干净的解决方案。干杯。 – 2009-08-21 13:55:31

2

a)我不认为你可以这样做有几个原因。首先,linq运算符用于评估表达式,因此不会影响源集合(或其他任何副作用)。其次,迭代器不允许在迭代期间修改源集合,因此在选择过程中没有任何机会去删除元素。

B)这是不太可能,这将给出任何性能优势 - 从列表中删除的项目为O(n),以便去除m项目将与O(MN),如果有很多的项目,以除去其中可能会相当缓慢。除非你真的需要空间,否则最好只是创建一个副本并使用它,在这种情况下,无论如何你都需要一个不同的数据结构。

相关问题