fox112358
fox112358

Reputation: 87

Linq get specific item from list of lists

Let's say I have such object

public class Example
{
   public List<Children> Children {get; set;}
}

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

public class Element
{
  public string Id {get; set;}
}

So I was basically doing

var result1 = example.Children.where(x => x.Children.Any(y => y.Elements.Where(z => z.Id == MyId)));
var actualRes = result1.Elements.Where(x => x.Id = MyId).FirstOrDefault();

But this seems to be very inefficient. Any ideas how to do this properly?

Thanks!

Upvotes: 1

Views: 1132

Answers (2)

Roar S.
Roar S.

Reputation: 10704

I was beaten by @Magnetron while writing the test case :-) This answer is a xUnit test for his answer.

using System.Collections.Generic;
using System.Linq;
using Xunit;

namespace XUnitTestProject.StackOverflow
{
    public class ElementsTests
    {
        [Theory]
        [MemberData(nameof(GenerateTestData), "~element3~")]
        public void Test(Example example, string idInTest)
        {
            // we should probably use SingleOrDefault instead of FirstOrDefault
            // when dealing with instance id
            var elementToFind = example.Children
                .SelectMany(children => children.Elements)
                .FirstOrDefault(element => element.Id.Equals(idInTest));

            Assert.NotNull(elementToFind);
            Assert.Equal(idInTest, elementToFind.Id);
        }

        public static TheoryData<Example, string> GenerateTestData(string idInTest) => new()
        {
            {
                new Example()
                {
                    Children = new List<Children>
                    {
                        new()
                        {
                            Id = "~child1~", Elements = new List<Element>
                            {
                                new() {Id = "~element1~"},
                                new() {Id = "~element2~"}
                            }
                        },
                        new()
                        {
                            Id = "~child2~", Elements = new List<Element>
                            {
                                new() {Id = idInTest},
                                new() {Id = "~element4~"}
                            }
                        }
                    }
                },
                idInTest
            }
        };
    }
}

Upvotes: 1

Magnetron
Magnetron

Reputation: 8543

Your code doesn't compile and have some erros. You can use SelectMany:

var actualRes = example.Children
    .SelectMany(x => x.Elements)
    .FirstOrDefault(x => x.Id == MyId);

Code with pre-populated examples:

Example example = new(){
    Children = new()
};
for(int i=0; i < 10; i++){
    Children c = new(){
        Id = i.ToString(),
        Elements = new()
    };
    example.Children.Add(c);
    for(int j=0; j < 10; j++){
        Element e = new(){
            Id=(10*i+j).ToString()
        };
        c.Elements.Add(e);
    }
}
string MyId="23";
var result1 = example.Children
    .SelectMany(x => x.Elements)
    .FirstOrDefault(x => x.Id == MyId);

Upvotes: 4

Related Questions