我正在使用LINQ从一组对象构建对象的树结构,这些对象是从存储过程调用中检索的。
我想知道是否
a)有任何方法可以将元素从一个集合中删除到新集合中
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
所以基本上;有没有办法做select语句,我实际上从initialCollection
中删除元素,因为我选择它们。这个想法是在递归构建我的树时减少要搜索的元素数量。这样做是否真的有任何好处,或者是从一个集合中删除元素并添加到另一个集合中的元素的开销太大了?
答案 0 :(得分: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
的调用是必要的,以防你有任何根元素没有子元素 - 如果指定的键不存在,我希望索引器抛出异常。但是文档不是很清楚 - 它可能会返回一个空序列。
答案 1 :(得分:2)
a)我认为你不能因为几个原因而这样做。首先,linq运算符用于计算表达式,因此不会影响源集合(或具有任何其他副作用)。其次,迭代器不允许在迭代期间修改源集合,因此无论如何都没有机会在选择期间删除元素。
b)这不太可能带来任何性能上的好处 - 从列表中删除项目是O(n),因此删除m项将是O(mn),如果要删除大量项目,这可能会非常慢。除非你真的想要空间,否则最好只创建一个副本并使用它,在这种情况下你还是想要一个不同的数据结构。