Reputation: 37908
I want to do something different on the last KeyValuePair
of the Dictionary
I'm iterating on.
For Each item In collection
If ItsTheLastItem
DoX()
Else
DoY()
End If
Next
Is this possible?
Re-Edit: I'm not using a Dictionary's values, I'm actually using a List of KeyValuePair
s. I've converted them and didn't notice later, dumb me.
Upvotes: 5
Views: 10871
Reputation: 71
Why not use:
List<string> list = new List<string>();
// add items
foreach (string text in list)
{
if (text.Equals(list[list.Count - 1]))
{
// last item
}
else
{
// not last item
}
}
Upvotes: 7
Reputation: 2767
I created a solution to build an IP String from 4 octets based on @CamiloMartin answer above.
String sIP;
StringBuilder sb = new StringBuilder();
List<String> lstOctets= new List<string>{ usrIP1.Text, usrIP2.Text, usrIP3.Text, usrIP4.Text };
foreach (String Octet in lstOctets.GetRange(0,lstOctets.Count - 1))
{
sb.Append(string.Format("{0:d}.", Octet));
}
if (lstOctets.Count == 4)
sb.Append(string.Format("{0:d}", lstOctets[lstOctets.Count - 1]));
else
sb.Append(string.Format("{0:d}.0", lstOctets[lstOctets.Count - 1]));
sIP = sb.ToString();
Upvotes: 1
Reputation: 37908
I just had an idea that doesn't use a counter.
For Each item In collection.GetRange(0, collection.Count - 1)
DoY(item)
Next
DoX(collection.Last)
Edit: sorry this is for a List, I had converted it before and intellisense gave me List methods instead of Dictionary methods.
Upvotes: 2
Reputation: 61497
Unless you want to implement the foreach
yourself, use a counter (C# code):
int count = collection.Count;
int counter = 0;
foreach(var item in collection)
{
counter++;
if(counter == count)
DoX();
else
DoY();
}
Please note that this will only work with non-streamed IEnumerable<T>
, also, depending on the implementation, Count
would cause the collection to be walked twice.
Upvotes: 8
Reputation: 241789
I would make your own extension method. This implementation here guarantees you only walk the collection once.
static class IEnumerableExtensions {
public static void ForEachExceptTheLast<T>(
this IEnumerable<T> source,
Action<T> usualAction,
Action<T> lastAction
) {
var e = source.GetEnumerator();
T penultimate;
T last;
if (e.MoveNext()) {
last = e.Current;
while(e.MoveNext()) {
penultimate = last;
last = e.Current;
usualAction(penultimate);
}
lastAction(last);
}
}
}
Usage:
Enumerable.Range(1, 5)
.ForEachExceptTheLast(
x => Console.WriteLine("Not last: " + x),
x => Console.WriteLine("Last: " + x)
);
Output:
Not last: 1
Not last: 2
Not last: 3
Not last: 4
Last: 5
Upvotes: 8
Reputation: 14874
foreach (var item in collection.Reverse().Skip(1))
{
}
// do here the stuff related to list.LastOrDefaut()
Another approach is to maintain the iteration index and when hit the collection.Length-2
or collection.Count()-2
then stop the loop and do whatever you want with last element.
But as @BrokenGlass said beware of side effects that it may has on your application.
And generally you must use Linq with special care.
For example every time you iterate on a linq to sql collection, you execute the query again, so it's much better to run it once eagerly by simply calling .ToList()
and use that in memory collection as much as you want.
Upvotes: 1
Reputation: 1503729
You can't do this naturally with an IEnumerable<T>
as you won't know whether there are any more elements until you try to get to the next one.
However, in my MiscUtil library I have something called SmartEnumerable
which reads one item in advance, in order to provide the following properties:
IsFirst
IsLast
Index
Value
See this page for usage instructions. For example:
For Each item In collection.ToSmartEnumerable()
If item.IsFirst
DoX()
Else
DoY()
End If
Next
You'd need to use item.Value
to get at the value of the current item.
One point about iterating over dictionaries though - they're not actually in any order. So while you can iterate and there will be a first entry and a last entry, you shouldn't assume that they'll be the first entry added and the last entry added respectively. That may not be a problem for your use case, but you ought to be aware of it.
Upvotes: 2
Reputation: 31743
With an Dictionary you have multiple options
Dim dictionary as new Dictionary(of String, MyObject)
For Each item in dictionary
// item is KeyValue pair
Next
For Each item in dictionary.Keys
// item is String
Next
For Each item in dictionary.Keys
// item is MyObject
Next
I would suggest you itterate over the ValueCollection and either use a counter or do a Equals comparison between the current and the last item (which will probably be slower but you save a counter variable ;) Don't forget to add a check of an empty list.
For Each item in dictionary.Values
If dictionary.Count > 0 AndAlso _
item.Equals(dictionary.Values(dictionary.Count - 1)) Then
Console.WriteLine("Last Item")
Else
Console.WriteLine("Some other Item")
End If
Next
Upvotes: 0
Reputation: 11903
Convert the collection to a list (like LINQ's ToList()) and iterate with a for(int i = 0)... loop.
Upvotes: 3