Identifying last loop when using for each
Solution 1:
I see a lot of complex, hardly readable code here... why not keep it simple:
var count = list.Length;
foreach(var item in list)
if (--count > 0)
Console.WriteLine("Looping: " + item);
else
Console.Writeline("Lastone: " + item);
It's only one extra statement!
Another common situation is that you want to do something extra or less with the last item, like putting a separator between the items:
var count = list.Length;
foreach(var item in list)
{
Console.Write(item);
if (--count > 0)
Console.Write(",");
}
Solution 2:
The foreach construct (in Java definitely, probably also in other languages) is intended to represent the most general kind if iteration, which includes iteration over collections that have no meaningful iteration order. For example, a hash-based set does not have an ordering, and therefore there is no "last element". The last iteration may yield a different element each time you iterate.
Basically: no, the foreach construct is not meant to be used that way.
Solution 3:
How about obtaining a reference to the last item first and then use it for comparison inside the foreach loop? I am not say that you should do this as I myself would use the index based loop as mentioned by KlauseMeier. And sorry I don't know Ruby so the following sample is in C#! Hope u dont mind :-)
string lastItem = list[list.Count - 1];
foreach (string item in list) {
if (item != lastItem)
Console.WriteLine("Looping: " + item);
else Console.Writeline("Lastone: " + item);
}
I revised the following code to compare by reference not value (can only use reference types not value types). the following code should support multiple objects containing same string (but not same string object) since MattChurcy's example did not specify that the strings must be distinct and I used LINQ Last method instead of calculating the index.
string lastItem = list.Last();
foreach (string item in list) {
if (!object.ReferenceEquals(item, lastItem))
Console.WriteLine("Looping: " + item);
else Console.WriteLine("Lastone: " + item);
}
Limitations of the above code. (1) It can only work for strings or reference types not value types. (2) Same object can only appear once in the list. You can have different objects containing the same content. Literal strings cannot be used repeatedly since C# does not create a unique object for strings that have the same content.
And i no stupid. I know an index based loop is the one to use. I already said so when i first posted the initial answer. I provided the best answer I can in the context of the question. I am too tired to keep explaining this so can you all just vote to delete my answer. I'll be so happy if this one goes away. thanks
Solution 4:
Is this elegant enough? It assumes a non-empty list.
list[0,list.length-1].each{|i|
puts "Looping:"+i # if not last loop iteration
}
puts "Last one:" + list[list.length-1]
Solution 5:
In Ruby I'd use each_with_index
in this situation
list = ['A','B','C']
last = list.length-1
list.each_with_index{|i,index|
if index == last
puts "Last one: "+i
else
puts "Looping: "+i # if not last loop iteration
end
}