C # - nested type query with LINQ

I have a model that looks like this:

public class MyType{
 public string Id {get;set;}
 public string Name{get;set;}
 public List<MyType> Children{get;set;}
}

and in my data I have only two levels of data, that is, my objects will look like this:

{
 MyType{"1","firstParent",
 {
  MyType{"2","firstChild",null},
  MyType{"3","secondChild",null}}
 },

 MyType{"4","secondParent",
 {
  MyType{"5","firstChild",null},
  MyType{"6","secondChild",null}}
 }
}

How can I request a MyType object with a specific identifier, where can it be a parent or a child?

Only parents are listed below.

collection.FirstOrDefault(c => c.id==id)
+4
source share
4 answers

You can create a list of all MyType, including children, and then query it like this:

collection.SelectMany(c => c.Children).Concat(collection).Where(c => c.id == id)
+3
source

You can use Anywith a recursive local function to search for objects at any level (your data structure seems to point to a deeper level)

bool hasIdOrChildren(MyType t, string localId)
{
    return t.Id == localId || (t.Children != null && t.Children.Any(o => hasIdOrChildren(o, localId)));
}
collection.FirstOrDefault(c => hasIdOrChildren(c, id));

Or using the pre C # 7 syntax:

Func<MyType, string, bool> hasIdOrChildren = null;
hasIdOrChildren = (MyType t, string localId) =>
{
    return t.Id == localId || (t.Children != null && t.Children.Any(o => hasIdOrChildren(o, localId)));
};
collection.FirstOrDefault(c => hasIdOrChildren(c, id));

, :

collection.FirstOrDefault(c => c.Id == id || (c.Children != null && c.Children.Any(o => o.Id == id)));

Edit

, - id, SelectMany :

IEnumerable<MyType> flattenTree(MyType t)
{
    if(t.Children == null)
    {
        return new[] { t };
    }
    return new[] { t }
        .Concat(t.Children.SelectMany(flattenTree));
};
collection
    .SelectMany(flattenTree)
    .FirstOrDefault(c => c.Id == id);

, .

+7

I think you are looking

var flattenedList = IEnumerable.SelectMany(i => i.ItemsInList);

This aligns the list and returns a single list with all the elements in it. In your case, you need to choose

collection.SelectMany(c => c.Type).Concat(collection).Where(item => item.Id == 5);

MSDN

You still have children in your own parents, but you can still erase or ignore them.

+1
source

I think you should smooth collectionusing the SelectMany method , then use FirstOrDefaultto get the elementid

MyType selected = collection
    .SelectMany(obj => new MyType[] {obj, obj.NestedList})
    .FirstOrDefault(obj => obj.id == id);
+1
source

Source: https://habr.com/ru/post/1695230/


All Articles