开发者

Simplifying code with LINQ (Collections within collections)

开发者 https://www.devze.com 2023-03-24 22:52 出处:网络
Given an object graph that looks something like the following; A --> B[] --> B1[] --> B2[] --> C[]

Given an object graph that looks something like the following;

A --> B[] --> B1[]
          --> B2[]   
  --> C[]

I need to check certain conditions on members/properties of B1 and B2 as well as ensuring that b2.Code appears somewhere within the C[]. If all conditions are satisfied, I then need to construct a new object using variables from elements of the C and B array. My current attempt is shown below, but I am wondering if this could be made more concise with LINQ?

   A a = GetA();
   List<MyTest> tsts = new List<MyTest>();
   foreach (B b in a.B)
    {
        foreach (B1 b1 in b.B1)
        {
            if (b1.State == ("READY"))
            {
                foreach (B2 b2 in b.B2)
                {
             开发者_如何转开发       var tst = (from c in a.C
                           where c.Code == b2.Code && !c.IsRedundant
                           select new MyTest
                           {
                               Code = c.Code,
                               BVal = b.BVal,
                               C1Val = c.C1                     
                           }).FirstOrDefault();
                    if (tst != null)
                        tsts.Add(tst);
                    break;
                }
            }
        }
    }


Absolutely. Basically each new foreach roughly equates to an extra from clause:

var tests = from b in GetA().B
            from b1 in b.B1
            where b1.State == "READY"
            from b2 in b.B2.Take(1)
            from c in a.C
                       .Where(x => x.Code == b2.Code && !c.IsRedundant)
                       .Take(1)
            select new MyTest
            {
                Code = c.Code,
                BVal = b.BVal,
                C1Val = c.C1                     
            };

var testList = tests.ToList();

A few notes on this:

  • It seems odd that you're never actually using b1, but you'll create an extra set of tests for each b1 which is in the "ready" state.
  • The unconditional break within the foreach (B2 b2 ...) loop basically means we only ever execute the loop body once - hence the Take(1)
  • The way you only use the first result of the innermost query is why I've got the inner query (expressed through extension methods) with a Take(1) call to get at most one result

It's quite possible that some of these oddities can be removed - but it's not clear what you're really trying to achieve, so I've just tried to make the code reproduce your original query as faithfully as possible.

0

精彩评论

暂无评论...
验证码 换一张
取 消