0

I would like to replace the foreach loop in the following code with LINQ ForEach() Expression:

    List<int> idList = new List<int>() { 1, 2, 3 };

    IEnumerable<string> nameList = new List<string>();

    foreach (int id in idList)
    {
       var Name = db.Books.Where(x => x.BookId == id).Select(x => x.BookName);
        nameList.Add(Name);
    }

Any Help Please!!

TanvirArjel
  • 30,049
  • 14
  • 78
  • 114
  • 2
    there's a [similar question](http://stackoverflow.com/questions/200574/linq-equivalent-of-foreach-for-ienumerablet) – lloyd Nov 23 '16 at 04:49
  • looks like you need to add a type declaration to Name, something like "var Name = db..." – Jacob Statnekov Nov 23 '16 at 04:50
  • @lloyd - That question **isn't** a duplicate. There's a difference between the C# keyword `foreach` and the `.ForEach` extension method. – Enigmativity Nov 23 '16 at 05:00

4 Answers4

5

Your code doesn't quite work (you're adding an IEnumerable<string> to a List<string>). You also won't need ForEach, since you're constructing the list:

You can do this:

var nameList = idList.SelectMany(id => db.Books.Where(x => x.BookId == id)
                     .Select(x => x.BookName)).ToList();

But then you're hitting the database for each ID. You can grab all the books at once with :

var nameList = db.Books.Where(b => idList.Contains(b.BookId))
                       .Select(b => b.BookName).ToList();

Which will only hit the database once.

Rob
  • 26,989
  • 16
  • 82
  • 98
1

Why not a select?

List<int> idList = new List<int>() { 1, 2, 3 };

List<string> nameList = idList
    .Select(id => db.Books.Where(x => x.BookId == id).Select(x => x.BookName))
    .ToList();

Or better yet: refactorise and select...

int[] idList = new int[] { 1, 2, 3 };

List<string> nameList = db.Books
    .Where(x => idList.Contains(x.BookId))
    .Select(x => x.BookName))
    .ToList();
Michael Coxon
  • 5,311
  • 1
  • 24
  • 51
0
    nameList.AddRange(
             db.Books.Where(x => idList.Contains(x.BookId))
                     .Select(x => x.BookName)
                     .ToList());

This will generate an IN statement in the SQL, thereby only doing a single select.

One thing to be aware of is the performance of IN degrades as the set (idList in this case) gets bigger. In the case of a large set, you can batch the set and do multiple queries:

int start = 0;
int batch = 1000;
while (start < idList.Count())
{
  var batchSet = idList.Skip(start).Take(batch);
  nameList.AddRange(
             db.Books.Where(x => batchSet.Contains(x.BookId))
                     .Select(x => x.BookName)
                     .ToList());
  start += batch;
}
benPearce
  • 37,735
  • 14
  • 62
  • 96
-1

To answer your specific question, you can do this:

List<int> idList = new List<int>() { 1, 2, 3 };

List<string> nameList = new List<string>();

idList.ForEach(id => {
    var Name = db.Books.Where(x => x.BookId == id).Select(x => x.BookName);
    nameList.Add(Name);
});
Thejaka Maldeniya
  • 1,076
  • 1
  • 10
  • 20