I am using nested foreach statements to carry out some functionality on embedded lists ...ie class properties which are themselves classes containing lists. I would like to do this using ling and lambda expressions
Take the following method
public int GetCount1()
{
int count1 = 0;
int count2 = o;
//This is the Setup code
FirstClass fc = new FirstClass
{
FirstList = new List<SecondClass>
{
new SecondClass
{
SecondList = new List<ThirdClass>
{
new ThirdClass
{
ThirdList = new List<FisrtStruct>
{
new FisrtStruct { int1=1, string1="one" },
new FisrtStruct{int1=2, string1="two" },
new FisrtStruct{ int1=3, string1="three" }
}
}
}
}
}
};
foreach (var item in fc.FirstList)
{
foreach (var item2 in item.SecondList)
{
foreach (var item3 in item2.ThirdList)
{
if (item3.int1 > 1)
{
count1++;
}
}
}
}
// I want something along the lines of
fc.FirstList
.ForEach(f =>
fc.FirstList.ForEach(fl =>
fl.SecondList.ForEach(sl =>
sl.ThirdList.ForEach(tl => t1.int1 > 1 { count2++} ))));
return "count1@ " + count1 + " and count2: " + count2;
}
I essentially want to replicate the functionality that increments count1 on count2, but using a much smoother lambda expressions.
Below is the component classes
class FirstClass
{
internal List<SecondClass> FirstList { get; set; }
}
class SecondClass
{
public List<ThirdClass> SecondList { get; set; }
}
class ThirdClass
{
internal List<FisrtStruct> ThirdList { get; set; }
}
struct FisrtStruct
{
internal int int1 { get; set; }
internal string string1 { get; set; }
}
Maybe it is something like this you want:
int count = fc.FirstList.SelectMany(f => f.SecondList).SelectMany(s => s.ThirdList).Count(t => t.Int1 > 1);
Maybe Rand Random was faster.
I think this will do it:
return fc.FirstList
.Select(i1 => i1.SecondList //within each FirstList, look at the SecondList property
.Select(i2 => i2.ThirdList //within each SecondList, look at the ThirdList property
.Count(i3 => i3.int1 > 1) //get the count for one/each ThirdList
).Sum() //sum all the ThirdList counts
).Sum(); //sum all the SecondList counts
Really, you want SelectMany()
instead of Select().Sum()
. This code was intended only as a bridge to build understanding what SelectMany()
will do, which would have come next... but someone else posted the SelectMany()
part of the solution before I got that far, and I didn't think it would be right to post basically that same code in my own answer.
I finished this much of the post because I still think it's useful to show this code as a teaching opportunity. It matches better what the loops were doing, and can therefore help build understanding for how the Linq operators and lambdas work.
Every foreach
or List.ForEach
can be converted to a LINQ call, either .Select()
or a from
in query form. List.ForEach
works only for lists anyway and doesn't do anything more than a foreach
Your nested foreach
calls can turn into :
var count= ( from item in fc.FirstList
from item2 in item.SecondList
from item3 in item2.ThirdList
where (item3.int1 > 1)
select item3
).Count();
The equivalent to nested from
s is SelectMany()
var count = fc.FirstList
.SelectMany(item=>item.SecondList)
.SelectMany(item=>item.ThirdList)
.Where(item=>item.int1>1)
.Count();
Count itself can have a predicate, which saves a line of code :
var count = fc.FirstList
.SelectMany(item=>item.SecondList)
.SelectMany(item=>item.ThirdList)
.Count(item=>item.int1>1);
or
var count= ( from item in fc.FirstList
from item2 in item.SecondList
from item3 in item2.ThirdList
select item3
).Count(item3.int1 > 1);
after installing resharper for some guidance, I was able to complete my though process. Below is a complete working console program file
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(GetCount1());
Console.ReadLine();
}
static string GetCount1()
{
int count1 = 0;
int count2 = 0;
int count3 = 0;
FirstClass fc = new FirstClass
{
FirstList = new List<SecondClass>
{
new SecondClass
{
SecondList = new List<ThirdClass>
{
new ThirdClass
{
ThirdList = new List<FisrtStruct>
{
new FisrtStruct { Int1= 1, String1= "one" },
new FisrtStruct{ Int1 = 2, String1= "two" },
new FisrtStruct{ Int1= 3, String1 = "three" }
}
}
}
}
}
};
foreach (var item in fc.FirstList)
{
foreach (var item2 in item.SecondList)
{
foreach (var item3 in item2.ThirdList)
{
if (item3.Int1 > 1)
{
count1++;
}
}
}
}
count2 = (from item in fc.FirstList from item2 in item.SecondList from item3 in item2.ThirdList select item3).Count(item3 => item3.Int1 > 1);
// Solution:
fc.FirstList
.ForEach(f => fc.FirstList
.ForEach(fl => fl.SecondList
.ForEach(sl => sl.ThirdList
.ForEach(tl =>
{
if (tl.Int1 > 1)
{
count3++;
}
}
))));
return "count1: " + count1 + " and count2: " + count2 + " and count3: " + count3;
}
}
class FirstClass
{
internal List<SecondClass> FirstList { get; set; }
}
class SecondClass
{
public List<ThirdClass> SecondList { get; set; }
}
class ThirdClass
{
internal List<FisrtStruct> ThirdList { get; set; }
}
struct FisrtStruct
{
internal int Int1 { get; set; }
internal string String1 { get; set; }
}
}
Hope it helps someone
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.