DEV Community

Bradley Wells
Bradley Wells

Posted on • Originally published at wellsb.com on

LINQ Collections and ForEach

Source

In this tutorial, you will learn how to use the ForEach method on Lists and other LINQ collections. This allows you to compactly write, on a single line of code, that which otherwise would take at least four lines.

Initial Setup

In the previous project, we started by creating a custom Book class designed to hold the title, author, and publication date of books. Then, we initialized a List<Book> variable containing ten books. Next, we filtered the list and performed some ordering operations. Finally, we printed our new list to the console. The code at the end of the previous tutorial may have looked something like the following. We will start with this as a baseline for this tutorial.

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

namespace IntroducingLINQ
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Book> bookList = new List<Book>()
            {
                new Book("Les Miserables", "Victor Hugo", 1862),
                new Book("L'Etranger", "Albert Camus", 1942),
                new Book("Le Tour du monde en quatre-vingts jours", "Jules Verne", 1869),
                new Book("Madame Bovary", "Gustave Flaubert", 1857),
                new Book("Le Comte de Monte-Cristo", "Alexandre Dumas", 1844),
                new Book("Vingt mille lieues sous les mers", "Jules Verne", 1872),
                new Book("Les Trois Mousquetaires", "Alexandre Dumas", 1844),
                new Book("Candide", "Voltaire", 1759),
                new Book("Notre-Dame de Paris", "Victor Hugo", 1831),
                new Book("Voyage au centre de la Terre", "Jules Verne", 1864)
            };

            var subList = bookList.Where(p => p.Author == "Jules Verne" || p.Author == "Victor Hugo")
                .OrderBy(p => p.Author)
                .ThenBy(p => p.PubDate);

            Console.WriteLine($"{subList.Count()} books match your search criteria:");

            foreach (Book book in subList)
            {
                Console.WriteLine($" {book.Author} - {book.Title} ({book.PubDate})");
            }

            Console.ReadLine();
        }
    }

    class Book
    {
        public string Title { get; set; }
        public string Author { get; set; }
        public int PubDate { get; set; }

        public Book(string title, string author, int pubDate)
        {
            Title = title;
            Author = author;
            PubDate = pubDate;
        }
    }
}

IEnumerable and ToList()

When we used the var keyword on Line 25, the compiler returned an IOrderedEnumerable type. This is an efficient data type when performing order operations on a set of data. For example, if the collection will be iterated over or re-ordered multiple times, there is no need to modify the original source list. In most scenarios, it is recommended to keep the returned data type.

However, there are certain operations that can be performed on lists, but which cannot be performed on an IEnumerable data types. For the sake of this tutorial, we will be performing one such operation. Fortunately, there is a way to convert an IOrderedEnumerable or IEnumerable to a List using the ToList() method.

You will need to modify Lines 25-27. First, explicitly define the data type as a Book<List>. Then, chain the .ToList() method onto the end of the operation. This will convert the IEnumerable type to a List<T>.

List<Book> subList = bookList.Where(p => p.Author == "Jules Verne" || p.Author == "Victor Hugo")
    .OrderBy(p => p.Author)
    .ThenBy(p => p.PubDate)
    .ToList();

LINQ Collections and ForEach

Now, we can replace the foreach statement from Lines 31-34 of the initial setup code.

subList.ForEach(p => Console.WriteLine($" {p.Author} - {p.Title} ({p.PubDate})"));

This line says that for each item in the list, write some information corresponding to that item to the console. This example is simple, and doesn’t have anything to do with operating on the actual data in the list. But, a collection’s ForEach() method can also be invoked to perform a number of other useful operations.

For example, suppose we decide to add a new property to the Book class – a book’s Sales Price.

public double SalePrice { get; set; }

Instead of setting the value of SalePrice at the time of instantiation, we could use the collection’s ForEach() method to assign all the books an initial price.

bookList.ForEach(p => p.SalePrice = 14.99);

Now, suppose your bookstore was having a special 2 euro off sale for all Jules Verne books. Before you learned about LINQ, you might have used the following code.

foreach (Book book in bookList)
{
    if (book.Author == &quot; Jules Verne&quot;)
    {
        book.SalePrice -= 2;
    }
}

With LINQ, however, all these lines of code can be replaced with a single line by chaining together a ForEach() looping statement with a Where() filtering method.

bookList.Where(p => p.Author == "Jules Verne").ToList().ForEach(p => p.SalePrice -= 2)

Your final project code may look similar to the following:

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

namespace IntroducingLINQ
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Book> bookList = new List<Book>()
            {
                new Book("Les Miserables", "Victor Hugo", 1862),
                new Book("L'Etranger", "Albert Camus", 1942),
                new Book("Le Tour du monde en quatre-vingts jours", "Jules Verne", 1869),
                new Book("Madame Bovary", "Gustave Flaubert", 1857),
                new Book("Le Comte de Monte-Cristo", "Alexandre Dumas", 1844),
                new Book("Vingt mille lieues sous les mers", "Jules Verne", 1872),
                new Book("Les Trois Mousquetaires", "Alexandre Dumas", 1844),
                new Book("Candide", "Voltaire", 1759),
                new Book("Notre-Dame de Paris", "Victor Hugo", 1831),
                new Book("Voyage au centre de la Terre", "Jules Verne", 1864)
            };

            bookList.ForEach(p => p.SalePrice = 14.99);

            bookList.Where(p => p.Author == "Jules Verne").ToList().ForEach(p => p.SalePrice -= 2);

            List<Book> orderedList = bookList.OrderBy(p => p.Author).ThenBy(p => p.PubDate).ToList();

            orderedList.ForEach(p => Console.WriteLine($"{p.SalePrice:C} - {p.Author} - {p.Title} ({p.PubDate})"));

            Console.ReadLine();
        }
    }

    class Book
    {
        public string Title { get; set; }
        public string Author { get; set; }
        public int PubDate { get; set; }
        public double SalePrice { get; set; }

        public Book(string title, string author, int pubDate)
        {
            Title = title;
            Author = author;
            PubDate = pubDate;
            //SalePrice = 14.99;
        }
    }
}

The Bottom Line

In this tutorial, you learned how to convert a generic IEnumerable type, IEnumerable<T>, to a generic list, List<T>. Remember, this will only be necessary if you need to perform certain operations that cannot be performed on an IEnumerable. You also learned how to use the ForEach() method with C# Lists. This allows you to compactly write in one line that which would otherwise take multiple lines of code. There is a lot more to discover with LINQ, so if you have questions, let me know in the comments!

Source

Top comments (1)

Collapse
 
saint4eva profile image
saint4eva

Another great article - very useful.