Get the last item in a foreach loop - c#

The question is straightforward. How can I get the last item in a foreach loop? Now I know I can find it starting an index and counting the items in the collection, but I was wondering if there is more elegant way?
foreach (var item in Collection)
{
}

You don't need foreach you can do that with Enumerable.Last
var lastItem = Collection.Last();
MSDN- Enumerable.Last<TSource> Method (IEnumerable<TSource>)
The Last(IEnumerable) method throws an exception if
source contains no elements. To instead return a default value when
the source sequence is empty, use the LastOrDefault method.

Just use Last:
Collection.Last() - This will return the last item in the list.

I would do it with Collection.Last() but you could do:
foreach (var item in Collection.Reverse())
... item is last on the first iteration
but the real question is why would you do this.

Related

How can I write list.GroupBy(x => x.AccountNumber).Select(g => g.First()) without LINQ

I need to analyze a task that starts with the code below but I couldn't figure out what the LINQ part is doing. Any leads are appreciated
foreach (var item in list.GroupBy(x => x.AccountNumber).Select(g => g.First()))
{
...
}
Some roughly-equivalent code (i.e. has the same function, but works slightly differently) would be:
var seenAccountNumbers = new HashSet<int>(); // Or some other data type?
foreach (var item in list)
{
if (seenAccountNumbers.Add(item.AccountNumber))
{
...
}
}
This code is a (somewhat wasteful) way of getting the first item by account number. It's wasteful because there's no reason to group everything before trying to find the first item per group.
The same thing can be implemented with an iterator function by iterating over all items in the input list and keeping track of all the AccountNumber values found so far. When a new one is found, yield it and add it to the tracking list. Or rather, HashSet.
In fact, that's how MoreLinq's DistinctBy operator is implemented :
var knownKeys = new HashSet<TKey>(comparer);
foreach (var element in source)
{
if (knownKeys.Add(keySelector(element)))
yield return element;
}
From the method's description:
Returns all distinct elements of the given source, where "distinctness"is determined via a projection and the default equality comparer for the projected type.
If a key is seen multiple times, only the first element with that key is returned.
The question's code can be replaced with :
foreach (var item in list.DistinctBy(x => x.AccountNumber))
{...
}
Create a dictionary, with the AccountNumber as Key, and put all your items from list, in that dictionary. That is about what happens.
You will overwrite items, with the same key, and a randomly last element, will stay in the dictionary. There is no order ensured when using GroupBy, so it doesn't matter if you choose First or Last element at the end, it just has the meaning of "pick one" (random).
var dict = new Dictionary<KeyType, ElementType>();
foreach(var item in list)
if (!dict.ContainsKey(item.AccountNumber))
dict[item.AccountNumber] = item;
You original iteration would now be
foreach(var item in dict.Values)
{
.....
}
To ask for Non-LINQ solution is not so strange, cause LINQ offers never the most performant solution, it's just short writing and fast coding.

foreach loop with conditions on a List object's attribute

I have a foreach loop that needs to iterate only if the 'Valid' property is set to true. Unfortunately if 'Valid' is set to false for the first item in the list it exits the entire loop.
Does anyone know the best method for using a condition in a foreach loop? Below is what I have right now.
foreach (var course in agentNewTraining.AllCoursesTaken.TakeWhile(c => c.Valid))
You can use the Where method.
foreach (var course in agentNewTraining.AllCoursesTaken.Where(c => c.Valid))
What your code does now is take elements until one which doesn't match the condition is found. In case the first element of your list, for example, doesn't match the predicate, you would get an empty collection.
Eve's answer above is correct.
I'd just like to point out that had you written your code in a more readable way, you could have solved this yourself very easily by stepping through the code.
var collectionToIterate = agentNewTraining.AllCoursesTaken.TakeWhile(c => c.Valid);
foreach (var course in collectionToIterate)
{
//...
}
You would have seen right away that the collectionToIterate was not what you expected. You were not "exiting the entire loop", you simply had no items to iterate over.
You can use Where instead:
foreach (var course in agentNewTraining.AllCoursesTaken.Where(c => c.Valid))
Or check the condition using an if statement:
foreach (var course in agentNewTraining.AllCoursesTaken) {
if (course.Valid) {
...
}
}

c# winform - how to delete multiple DataGridViewRows

Here is my code:
foreach (DataGridViewRow r in dgv01.Rows)
if (r.Cells[0].Value.ToString() == abc)
{
dgv01.Rows.Remove(r);
//dgv01.CurrentCell = dgv01.Rows[0].Cells[0]; - **also tried**
}
But only some rows are deleted - not all specified !?
Why - foreach - does not mean - foreach ?
I have to remind you that it is dangerous to use a foreach block when you want to modify/remove the data being traversed. The removal messes up with the index of the foreach iterator.
Solution? Use a reverse for loop instead.
First of all it is not a good idea to change collection inside foreach loop. Secondly foreach is not behaving how you want because once the first row is removed then second row will become the first row but because in foreach the checking will be done on second row which is actually a third row. so, checking on the second row has been skipped. The best way to do is use for loop in a reverse order.
to know why foreach is not behaving like foreach try this simple example.
private List<int> list = Enumerable.Range(0, 10).ToList<int>();
for(int i=0;i<list.Count;++i)
{
if (list[i] < 5)
list.RemoveAt(i);
}
list.ForEach(x => Console.Write(x));
Output:
1356789
When you iterate over a collection using foreach, the collection should not be modified otherwise, in the best of scenarios, you end up not covering the entire collection. Most of the time, however, modifying the collection while within a foreach block, the iteration will fail.
In order to remove the rows from the DataGridView, you'll have to use a for iteration block or a two-step process both of which I display below.
for Iteration Block
This procedure uses an index to traverse the collection, modifying the collection as you go. The thing you need to know here is that if you intend to modify the collection, you do not have the index increment (go forward through the collection); you decrement the index (go backwards through the collection). If you modify (remove or add items) the collection while iterating forwards, you may not end up visiting all the items in the collection.
Here is code to remove rows from the DataGridView. Remember, we iterate backwards.
for (int i = dgv01.Rows.Count - 1; i >= 0; i--)
{
if (dgv01.Rows[i].Cells[0].Value.ToString() == "abc")
{
dgv01.Rows.RemoveAt(i);
}
}
foreach Iteration Block
This procedure uses a two-step approach. The first step finds the items to be removed and the second step removes the items from the collection. This two-step process is necessary for the reasons I explained earlier.
Now the code. Remember, it is a two-step process.
// step 1. find the items to be removed
//items to be removed will be added to this list
var itemsToRemove = new List<DataGridViewRow>();
foreach (DataGridViewRow r in dgv01.Rows)
{
if (r.Cells[0].Value.ToString() == "abc")
{
itemsToRemove.Add(r);
}
}
//step 2. remove the items from the DataGridView
foreach (var r in itemsToRemove)
{
// this works because we're not iterating over the DataGridView.
dgv01.Rows.Remove(r);
}
One last thing you should know is that the procedures I have demonstrated here do not apply to the DataGridViewRowCollection class only; it applies to all collections that implement the IList<T> or the ICollection<T> interface. So, yes, the process can be used for Lists, Dictionaries, ControlCollections and all other similar classes.
do a descending sorting on column[0] then from bottom u can delete the rows. Once abc is over u can break the loop also.
Other wise u can put a row filter on dataTable u are using.
((DataTable)this.datagrid1.DataSource).DefaultView .RowFilter
Whenever I have to modify a collection inside a foreach I usually make a new collection which I fill with the data I want to modify, and then loop through this second collection to do the actual changes to the main collection. In this way I never modify a collection while looping it, so I avoid the situation described by MChicago.
In your case I usually would write this kind of code:
List<DataGridViewRow> toDel = new List<DataGridViewRow>();
foreach (DataGridViewRow r in dgv01.Rows)
if (r.Cells[0].Value.ToString() == "abc")
toDel.Add(r);
foreach (DataGridViewRow aRow in toDel)
dgv01.Rows.Remove(aRow);

would remove a key from Dictionary in foreach cause a problem? or should I better to construct a new Dictionary?

for example:
1.
foreach (var item in myDic)
{
if (item.value == 42)
myDic.remove(item.key);
}
would the iterator works properly no matter how the statements in the inner brackets could possibly affect myDic?
2.
var newDic = myDic.where(x=>x.value!=42).ToDictionary(x=>x.key,x=>x.value);
Is 2nd approach a good practice? functional programming and immutable?
The first approach will crash at runtime, since the enumerator makes sure that nobody deletes from the underlying collection while it's enumerating.
The second approach is a nice thought, but C# dictionaries are mutable and it's neither idiomatic nor efficient to copy them around if you can accomplish the same thing with mutation.
This is a typical way:
var itemsToRemove = myDic.Where(f => f.Value == 42).ToArray();
foreach (var item in itemsToRemove)
myDic.Remove(item.Key);
EDIT: In response to your question in the comments. Here's how the example in your other question works:
myList = myList.where(x=>x>10).select(x=>x-10);
This line of code doesn't run anything; it's totally lazy. Let's say for the sake of argument that we have a foreach after it to make it look more like this question's example.
foreach (int n in myList)
Console.WriteLine(n);
When that executes, here's what'll happen on each iteration:
Call MoveNext on the enumerator
The enumerator finds the next value greater than ten
Then it takes that value minus ten and sets the Current property to that
Binds the Current property to the variable n
Console.WriteLines it
You can see that there's no mystery and no infinite loop and no whatever.
Now compare to my example, supposing we left out the ToArray.
var itemsToRemove = myDic.Where(f => f.Value == 42);
foreach (var item in itemsToRemove)
myDic.Remove(item.Key);
Call MoveNext on the enumerator
The enumerator finds the next pair with value 42 and sets the Current property to that
Binds the Current property to the variable item
Removes it
This doesn't work because while it's perfectly fine to WriteLine something from a collection while you have an enumerator open on it, you aren't permitted to Remove something from a collection while you have an enumerator open on it.
If you call ToArray up front, then you start out by enumerating over the dictionary and populating the array. When we get to the foreach, the foreach statement has an enumerator open on the array, not the dictionary. You're allowed to remove from the dictionary as you iterate over the array.
Also you can iterate over the copy of your collection:
foreach (var item in myDic.ToList())
{
if (item.value == 42)
myDic.remove(item.key);
}
notice myDic.ToList() in foreach statement.
According to the docs, starting from .NET Core 3.0, removing an element will no longer affect active enumerators. You can safely remove an item while iterating:
foreach (var item in myDic)
{
if (item.Value == 42)
myDic.Remove(item.Key);
}
Dictionary<TKey,TValue>.Remove Method
.NET Core 3.0+ only: this mutating method may be safely called without invalidating active enumerators on the Dictionary<TKey,TValue> instance. This does not imply thread safety.
I would suggest making a copy of the keys and not the entire dictionary as an array, like others have suggested.
mykeytype[] mykeys = new mykeytype[mydic.Keys.Count];
mydic.Keys.CopyTo(mykeys, 0);
foreach (var key in mykeys)
{
MyType thing;
if (!mydic.TryGetValue(key, out thing)) continue;
// remove or add to dictionary here
}

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?
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.
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.
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.
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.

Categories

Resources