Xaisoft
Xaisoft

Reputation: 46651

Explain this LINQ code?

I asked a question in which one of the response contained the following LINQ code:

var selected = lstAvailableColors.Cast<ListItem>().Where(i => i.Selected).ToList();
selected.ForEach( x => { lstSelectedColors.Items.Add(x); });
selected.ForEach( x => { lstAvailableColors.Items.Remove(x);});

Can someone explain the above LINQ to a total newbie?

Upvotes: 1

Views: 570

Answers (4)

Daniel Earwicker
Daniel Earwicker

Reputation: 116764

Maybe some translations would help

var selected = lstAvailableColors.Cast<ListItem>().Where(i => i.Selected).ToList();

could be written as:

List<ListItem> selected = new List<ListItem>();

foreach (ListItem item in lstAvailableColors)
{
    if (item.Selected)
        selected.Add(item);
}

Note that foreach implicitly casts the items on the list to whatever type the loop variable is, in this case ListItem, so that takes care of the Cast<ListItem> on the list. Where filters out any items for which the expression is false, so I do the same thing with an if statement. Finally, ToList turns the sequence into a list, so I just build up a list as I go. The end result is the same.

And:

selected.ForEach( x => { lstSelectedColors.Items.Add(x); });
selected.ForEach( x => { lstAvailableColors.Items.Remove(x); });

could be written as:

foreach (ListItem item in selected)
{
    lstSelectedColors.Items.Add(item);
    lstAvailableColors.Items.Remove(item);
}

I doubt if there's a good reason for writing it the more obscure way in that case.

Upvotes: 1

Neil Williams
Neil Williams

Reputation: 12578

The LINQ operators use what's called a fluent interface, so you can read the first line as a series of function calls. Assuming that lstAvailableColors is IEnumerable<T>, the idea is that each available color flows through the LINQ operators.

Let's break it down:

var selected = lstAvailableColors
    // each item is cast to ListItem type
    .Cast<ListItem>() 
    // items that don't pass the test (Selected == true) are dropped
    .Where(i => i.Selected) 
    // turn the stream into a List<ListItem> object
    .ToList();

EDIT: As JaredPar pointed out, the last line above (ToList()) is very important. If you didn't do this, then each of the two selected.ForEach calls would re-run the query. This is called deferred execution and is an important part of LINQ.

You could rewrite this first line like this:

var selected = new List<ListItem>();

foreach (var item in lstAvailableColors)
{
    var listItem = (ListItem)item;

    if (!listItem.Selected)
         continue;

    selected.Add(listItem);
}

The last two lines are just another way to write a foreach loop and could be rewritten as:

foreach (var x in selected)
{
    lstSelectedColors.Items.Add(x);
}

foreach (var x in selected)
{
    lstAvailableColors.Items.Remove(X);
}

Probably the hardest part of learning LINQ is learning the flow of data and the syntax of lambda expressions.

Upvotes: 5

JaredPar
JaredPar

Reputation: 755587

Explanation from original question.

The LINQ version works in two parts. The first part is the first line which finds the currently selected items and stores the value in a List. It's very important that the line contain the .ToList() call because that forces the query to execute immediately vs. being delayed executed.

The next two lines iterate through each value which is selected and remove or add it to the appropriate list. Because the selected list is already stored we are no longer enumerating the collection when we modify it.

Upvotes: 3

tvanfosson
tvanfosson

Reputation: 532765

It casts each item in the list to type ListItem, then selects only those whose Selected property is true. It then creates a new list containing just these items. For each item in the resulting list, it adds that item to the selected colors list and removes it from the available colors list.

Upvotes: 2

Related Questions