Find top level parent in a list with LINQ
I have a list of custom objects that have an ID and a ParentID. The list looks something like this.
ParentID ID
123 345
123 456
456 567
456 678
678 789
I need a LINQ statement to find the top level parent; that is, all objects where ParentID does not exist as an identifier (in this example there are only 123).
Here is what I have so far and am returning 567 678 789.
parentList = baseList.Where(b => !baseList.Select(o => o.ParentID).Distinct().Contains(b.ID)).ToList();
source to share
Your current query is trying to find all elements where their id does not match any other parent element id - in other words, you find all childless nodes.
It sounds like what you want is all parent nodes - those whose parent id doesn't match another element id.
var ids = new HashSet<int>(baseList.Select(o => o.ID));
var itemsWithNoParent = baseList.Where(o => !ids.Contains(o.ParentID))
.ToList();
I am using HashSet<>
to provide reasonable performance .Contains()
for large collections.
source to share
also:
parentList = baseList
.where(parent => !baseList.Any(possibleParent => possibleParent.ID == parent.ParentID))
.ToList();
I use this a lot for small (less than 100,000) collections.
I might as well add this; how easy is it to create a tree view from this:
public class Node
{
public int Id { get; set; }
public int ParentId { get; set; }
public IEnumerable<Node> Nodes { get; set; }
public Node ParentNode { get; set; }
}
IEnumerable<Node> nodes = .....
nodeTree = nodes.Select(n =>
{
n.Nodes = nodes.Where(n2 => n2.ParentId == n.Id).ToList();
n.ParentNode = nodes.FirstOrDefault(n2 => n2.Id == n.ParentId)
return n;
})
.Where(n => n.ParentNode == null)
.ToList();
source to share