Precisely how is the exit condition in a for loop computed? - c#

NOTE: see edit below before you read this.
I have a function that takes in a string and outputs an enum of a specified type if that string matches any members of that enum. I.e., I have some enum SupportedFunctions with members CVT, VIS, etc, and the function will return SupportedFunctions.CVT when passed "CVT".
I have the following two functions:
parse_enum:
private bool parse_enum<EnumType>(string input, out EnumType out_enum)
{
EnumType current_enum = (EnumType)(object)0;
bool seeking = current_enum.ToString() != "0";
for (int i = 0; seeking; i++)//THIS LINE
{
current_enum = (EnumType)(object)i;
Console.WriteLine(current_enum);
seeking = current_enum.ToString() != i.ToString();
if (current_enum.ToString().ToLower() == input)
{
out_enum = current_enum;
return true;
}
}
and parse_enum_2:
private bool parse_enum_2<EnumType>(string input, out EnumType out_enum)
{
EnumType current_enum = (EnumType)(object)0;
for (int i = 0; current_enum.ToString() != i.ToString(); i++)//THIS LINE
{
current_enum = (EnumType)(object)i;
Console.WriteLine(current_enum);
if (current_enum.ToString().ToLower() == input)
{
out_enum = current_enum;
return true;
}
}
Note that both functions are exactly the save save for one thing: parse_enum computes the logical seeking and uses that for the loop exit condition, while parse_enum_2 computes the equivalent expression for seeking in the for loop statement and uses that.
The WriteLine statement is temporary for debugging. The strange thing is that parse_enum works just fine, i.e. has output
VIS
CVT
CLR
3 <-----terminates since it has exhausted enum terms
while parse_enum_2 has output
VIS
CVT
CLR
3
4
5
6
7
...
and never exits.
Why is this? I realize that there is an easier way to do this, but that is not the point here. I did a trick like this a while ago and compiled using CSC and it seemed to work. I am using Mono on Ubuntu at the moment, might that be making the difference?
EDIT: Thanks to those of you who have described how the condition works, but I do believe my question is more subtle than that. I will simplify the code: I have two functions:
Here is the first one, func1:
private static void func1()
{
ConsoleColor current = (ConsoleColor)0;
bool end = current.ToString() == 0.ToString();
for (int i = 0; !end; i++)//HERE
{
current = (ConsoleColor)i;
end = current.ToString() == i.ToString();
Console.WriteLine("enum:" + current + ", i:" + i + ", condition:" + end);
Console.ReadLine();//For stepping through
}
}
and the second one, func2:
private static void func2()
{
ConsoleColor current = (ConsoleColor)0;
for (int i = 0; current.ToString() != i.ToString(); i++)//HERE
{
current = (ConsoleColor)i;
Console.WriteLine("enum:" + current + ", i:" + i + ", condition:" + (current.ToString() != i.ToString()));
Console.ReadLine();//For stepping through
}
}
I have simplified the code so there isn't as much going on. I have printed i, the name of the current enum and the exit condition: the logical end in the first case, and the equivalent expression in the second case. This is the output I get:
For func1:
enum:Black, i=0, condition:True
enum:DarkBlue, i=1, condition:True
...
enum:White, i=15, condition:True
enum:16, i=16, condition:False //Program terminates
but for func2:
enum:Black, i=0, condition:True
enum:DarkBlue, i=1, condition:True
...
enum:White, i=15, condition:True
enum:16, i=16, condition:False
enum:17, i=17, condition:False
enum:18, i=18, condition:False
... //Program does not terminate
Perhaps I asked this the wrong way. However, it is very clear in the second case that current.ToString() != i.ToString() returns false, yet the loop keeps going. Again, I think this is actually a far more subtle issue than it appears. Perhaps I am missing something glaringly obvious?

The language reference states that the condition section executes before each loop iteration.
The condition section, if present, must be a boolean expression. That expression is evaluated before every loop iteration. If the condition section is not present or the boolean expression evaluates to true, the next loop iteration is executed; otherwise, the loop is exited.
The iterator section happens after each loop iteration.
The iterator section defines what happens after each iteration of the body of the loop.
Given your example, i will increment at the end of the loop, and then the new value of i will be compared to the value of current_enum before current_enum is assigned to the new value of i.

Related

Counting a string to ensure the input is within a min/max boundary

For a part of my project, I want to enforce the rule that the user input can only be within a min/max word boundary. With a minimum of 1 word, and a maximum of 50 words. The boolean isn't changing from the default set value of false. Here is my code:
bool WordCount_Bool = false;
//Goto the method that handles the calculation of whether the users input is within the boundary.
WordCount_EH(WordCount_Bool);
//Decide whether to continue with the program depending on the users input.
if (WordCount_Bool == true)
{
/*TEMP*/MessageBox.Show("Valid input");/*TEMP*/
/*Split(split_text);*/
}
else
{
MessageBox.Show("Please keep witin the Min-Max word count margin.", "Error - Outside Word Limit boundary");
}
Method handling the array and the change of the boolean:
private bool WordCount_EH(bool WordCount_Bool)
{
string[] TEMPWordCount_Array = input_box.Text.Split(' ');
int j = 0;
int wordcount = 0;
for (int i = 100; i <=0; i--)
{
if (string.IsNullOrEmpty(TEMPWordCount_Array[j]))
{
//do nothing
}
else
{
wordcount++;
}
j++;
}
if (wordcount >= 1)
{
WordCount_Bool = true;
}
if (wordcount < 1)
{
WordCount_Bool = false;
}
return WordCount_Bool;
}
Thank you all in advance.
Side note: I realize that the for loop will throw an exception or at least is not optimal for its purpose so any advice will be much appreciated.
Extra Side note: Sorry I should have said that the reason i haven't used length is that wherever possible I should do my own code instead of using built-in functions.
The short answer is you should just return a true or false value from your WordCount_EH method like others have said
But just to clear up why it doesn't work. C# by default passes arguments by value. With Value types such as Boolean the actual value of true or false is stored in the variable. So when you pass your Boolean value into your method all you are doing is saying please put this bool value into my new variable (the method parameter). When you make changes to that new variable it only changes that variable. It has no relation to the variable that it was copied from. This is why you don't see a change in original bool variable. You may have named the variables the same but they are infact two different variables.
Jon Skeet explains it fantastically here http://jonskeet.uk/csharp/parameters.html
Here you go this should solve it:
if(input_box.Text.Split(' ').Length>50)
return false;
else
return true;
You need to pass WordCount_Bool by ref if you want to change it in WordCount_EH:
private bool WordCount_EH(ref bool WordCount_Bool) { ... }
bool WordCount_Bool = false;
WordCount_EH(ref WordCount_Bool);
although in this case you might as well use the return value:
bool WordCount_Bool = false;
WordCount_Bool = WordCount_EH(WordCount_Bool);
If you want to pass argument by reference, you need to do as per #Lee suggestion.
For your logic implementation, you can use following code to avoid array indexing.
// It would return true if you word count is greater than 0 and less or equal to 50
private bool WordCount_EH()
{
var splittedWords = input_box.Text.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();
return (splittedWords.Count > 0 && splittedWords.Count <= 50);
}

Why do these errors appear? c# - hangman game

I'm fairly new to coding (especially c#) - this is an assignment for a programming fundamentals class - I'm not looking for the answer - I'm looking for someone to explain why I get these two 'error's for a boolean method I'm supposed to create to check if the user's guess for a letter or the full word in a game of hangman.
The errors I get are - 'Unreachable Code detected - for the idx++ part - which doesn't make sense as I've used it in other separate methods..
And Program.CheckGuess(char[], char[], char[], string: not all code paths return a value.
I know I'm not fully finished the aspect. It's probably staring at me in the face - just looking for some guidance. Thanks.
static bool CheckGuess(char[] secrets, char[] mask, char[] letters, string guess)
{
int misses = 0; bool condition = false;
for (int idx = 0; idx < secret.Length; idx++)
{
guess.ToCharArray();
if (mask[idx] == guess[idx])
{
//reveal character or word
condition = true;
}
else
{
misses = misses + 1;
condition = false;
}
return condition;
}
}
You should understand that a return statement, when executed, makes the control jump out of the method and back to the caller.
In your code, your return is statement is placed inside the for loop. When an iteration of the for loop is executed, the control jumps out of the method immediately and goes back to the caller of the method.
As you know, the last part in a for loop header (idx++) is executed when an iteration has finished executing. However, in your case, an iteration will never finish because it just jumps back to the caller when control reaches return. This is why the first error occurred.
You should also understand that every method which doesn't have void as the return type needs to return no matter what.
So what if the for loop's condition (the middle part) is never true? The for loop will never be executed, right? If the for loop isn't executed, then what should the method return?
The error says that not all code path returns a value because the method would not return if the for loop isn't executed.
To fix this, you just need to move the return statement out of the for loop:
static bool CheckGuess(char[] secrets, char[] mask, char[] letters, string guess)
{
int misses = 0; bool condition = false;
for (int idx = 0; idx < secret.Length; idx++)
{
guess.ToCharArray();
if (mask[idx] == guess[idx])
{
//reveal character or word
condition = true;
}
else
{
misses = misses + 1;
condition = false;
}
}
return condition;
}
Because you have a return statement.
When this return inside your for loop is reached, the program jumps out of the loop and thus makes you i++ unreachable.

bugs in java code after converting from C#

here is a function prints repeating int in a array.
in c#:
int [] ReturnDups(int[] a)
{
int repeats = 0;
Dictionary<int, bool> hash = new Dictionary<int>();
for(int i = 0; i < a.Length i++)
{
bool repeatSeen;
if (hash.TryGetValue(a[i], out repeatSeen))
{
if (!repeatSeen)
{
hash[a[i]] = true;
repeats ++;
}
}
else
{
hash[a[i]] = false;
}
}
int[] result = new int[repeats];
int current = 0;
if (repeats > 0)
{
foreach(KeyValuePair<int,bool> p in hash)
{
if(p.Value)
{
result[current++] = p.Key;
}
}
}
return result;
}
now converted to JAVA by Tangible software's tool.
in java:
private int[] ReturnDups(int[] a)
{
int repeats = 0;
java.util.HashMap<Integer, Boolean> hash = new java.util.HashMap<Integer>();
for (int i = 0; i < a.length i++)
{
boolean repeatSeen = false;
if (hash.containsKey(a[i]) ? (repeatSeen = hash.get(a[i])) == repeatSeen : false)
{
if (!repeatSeen)
{
hash.put(a[i], true);
repeats++;
}
}
else
{
hash.put(a[i], false);
}
}
int[] result = new int[repeats];
int current = 0;
if (repeats > 0)
{
for (java.util.Map.Entry<Integer,Boolean> p : hash.entrySet())
{
if (p.getValue())
{
result[current++] = p.getKey();
}
}
}
return result;
}
but findbug find this line of code as bugs. and it looks very odd to me too.
if (hash.containsKey(a[i]) ? (repeatSeen = hash.get(a[i])) == repeatSeen : false)
can someone pls explain to me what this line does and how do i write it in java properly?
thanks
You have overcomplicated the code for TryGetValue - this simple translation should work:
if ( hash.containsKey(a[i]) ) {
if (!hash.get(a[i])) {
hash.put(a[i], true);
}
} else {
hash.put(a[i], false);
}
C# has a way to get the value and a flag that tells you if the value has been found in a single call; Java does not have a similar API, because it lacks an ability to pass variables by reference.
Do not directly convert C# implementation. assign repeatSeen value only if the id is there.
if (hash.containsKey(a[i]))
{
repeatSeen = hash.get(a[i]).equals(repeatSeen)
if (!repeatSeen)
{
hash.put(a[i], true);
repeats++;
}
}
To answer the actual question that was asked:
if (hash.containsKey(a[i]) ? (repeatSeen = hash.get(a[i])) == repeatSeen : false)
is indeed syntactically wrong. I haven't looked at the rest of the code, but having written parsers/code-generators in my time I'm guessing it was supposed to be
if (hash.containsKey(a[i]) ? (repeatSeen = hash.get(a[i])) == repeatSeen) : false)
It's gratuitously ugly -- which often happens with code generators, especially ones without an optimizing pass -- but it's syntactically correct. Let's see if it actually does have a well-defined meaning.
CAVEAT: I haven't crosschecked this by running it -- if someone spots an error, please tell me!
First off, x?y:z is indeed a ternary operator, which Java inherited from C via C++. It's an if-then-else expression -- if x is true it has the value y, whereas if x is false it has the value z. So this one-liner means the same thing as:
boolean implied;
if (hash.containsKey(a[i]) then
implied = (repeatSeen = hash.get(a[i])) == repeatSeen);
else
implied = false;
if(implied)
... and so on.
Now, the remaining bit of ugliness is the second half of that and-expression. I don't know if you're familiar with the use of = (assignment) as an expression operator; its value as an operator is the same value being assigned to the variable. That's mostly intended to let you do things like a=b=0;, but it can also be used to set variables "in passing" in the middle of an expression. Hardcore C hackers do some very clever, and ugly, things with it (he says, being one)... and here's it's being used to get the value from the hashtable, assign it to repeatSeen, and then -- via the == -- test that same value against repeatSeen.
Now the question is, what order are the two arguments of == evaluated in? If the left side is evaluated first, the == must always be true because the assignment will occur before the right-hand side retrieves the value. If the right side is evaluated first, we'd be comparing the new value against the previous value, in an very non-obvious way.
Well, in fact, there's another StackOverflow entry which addresses that question:
What are the rules for evaluation order in Java?
According to that, the rule for Java is that the left argument of an operator is always evaluated before the right argument. So the first case applies, the == always returns true.
Rewriting our translation one more time to reflect that, it turns into
boolean implied;
if (hash.containsKey(a[i]) then
{
repeatSeen = hash.get(a[i]));
implied = true;
}
else
implied = false;
if(implied)
Which could be further rewritten as
if (hash.containsKey(a[i]) then
{
repeatSeen = hash.get(a[i]));
// and go on to do whatever else was in the body of the original if statement
"If that's what they meant, why didn't they just write it that way?" ... As I say, I've written code generators, and in many cases the easiest thing to do is just make sure all the fragments you're writing are individually correct for what they're trying to do and not worry about whether they at all resemble what a human would have written do do the same thing. In particular, it's tempting to generate code according to templates which allow for cases you may not actually use, rather than trying to recognize the simpler situation and generate code differently.
I'm guessing that the compiler was drawing in and translating bits of computation as it realized it needed them, and that this created the odd nesting as it started the if, then realized it needed a conditional assignment to repeatSeen, and for whatever reason tried to make that happen in the if's test rather than in its body. Believe me, I've seen worse kluging from code generators.

c# syntax question - for loop and end of line

I am currently learning c# and reading a few books. I can do quite a few things, however only from modifying examples - it really frustrates that I do not actually understand how/why some of the more basic items work.
I have just done a console application that takes arguments and displays them all one by one.
The code is:
using System;
class test
{ static int Main(string[] argsin)
{
for (
int i = 0;
i < argsin.Length;
i++
)
Console.WriteLine("Argument: {0}", argsin[i]);
Console.ReadLine();
return -1;
}
}
Now, this works perfectly, but coming from a basic (no pun!) understand of Visual Basic, how/why does it know to print the correct argument and then go on to the next without quitting the application after the first Console.WriteLine... I feel I have missed the fundamentals of how this works!
Next, why is it that inside the for loop, each line ends with a semicolon apart from i++?
I keep forgetting to add it from time to time, and then when trying to work out why it wasn't compiling, I added one where I wasn't meant to!
Your code is formatted a bit strangely, if you reformat it as this I think it's easier to understand:
using System;
class test
{
static int Main(string[] argsin)
{
for (int i = 0; i < argsin.Length; i++)
{
Console.WriteLine("Argument: {0}", argsin[i]);
}
Console.ReadLine();
return -1;
}
}
So as you can see int i = 0; i < argsin.Length; i++ are not 3 different lines, they are all just arguments to the for loop.
And adding the { and } makes it easier to see what lines of code are inside the for loop.
I will try to explain the loop by comparing to VB syntax.
In C#: for (int i = 0; i < 5; i++)
In VB: For i = 0 To 4
The i = 0 part is the same in both, so I guess it's clear - this is used to initialize the loop iterator.
The i < 5 part in C# becomes 0 to 4 in VB.... you can think of this as though VB is doing a "shortcut", but the meaning in both is the same: that is the loop condition, i.e. what is the condition that the loop will keep running, in this case the loop will keep running as long as i is less then 5.
And finally, the i++ part which is required in C# to tell "what will happen to the iterator after each iteration?" is not needed in good old friendly VB that will simply increment it by 1 for you, always - by default.
Why having semicolon after each part of the loop? Because each part has its own meaning and usage so the compiler must know how to separate the parts when building the final code. Why not having semicolon after the i++ part? Same reason that you don't have comma after last argument passed to function e.g. Console.WriteLine("Argument: {0}", argsin[i], );
About the loop having no "block" only one line, it was explained in the other answers, rule of thumb is that C# allow single line blocks to appear without the brackets.
By convention c# and all c like languages when presented with a for loop (or and if statement etc) will run the line immediately after. Personally I don't like writing code like this, i feel it lacks readability.
To clarify we can add curly braces to denote scope
for (
int i = 0;
i < argsin.Length;
i++
)
{
Console.WriteLine("Argument: {0}", argsin[i]);
}
Console.ReadLine();
return -1;
now what the for loop executes is clearly defined (and if we wanted to do more in our loop we would add the extra instructions in between the curly braces).
edit:
The reason for the semi colons as you define your for loop is that each part of that definition is a separate statement.
int i = 0; //creates an integer i and sets its value to 0
i < argsin.Length; sets our comparison operation to define when the loop ends
i++ //what to do at the end in this case increment i by 1
Each needs to be treated independent of the others and as the semi colon denotes the end of a statement in c# (which is why each line ends in it) we use it to break up the statements so the compiler can read it.
While the 2 semicolons are mandatory the arguments are not we could if we wanted change it to be this.
int i = 0;
for (;;)
{
if(i>=argsin.Length){
break;
}
Console.WriteLine("Argument: {0}", argsin[i]);
i++;
}
This is functionally identical to the way you wrote it but I've moved all the logic out of the for statement to its equivalent position inside (or outside in the case of defining i) the loop
The reason why you application prints the right number of arguments is that the WriteLine statement is part of the loop. In C# if you've only got one line of code after a for statement then you don't need curly brackets. (This is the same for if too)
So
for (int i = 0; i < argsin.Length; i++)
Console.WriteLine("Argument: {0}", argsin[i]);
is the same as
for (int i = 0; i < argsin.Length; i++)
{
Console.WriteLine("Argument: {0}", argsin[i]);
}
As the for the semi-colon after the i++ thats just how it is. Normally the for statement is written on one line as I've done in my samples above.
Hope this helps.
I've brushed your formatting a little up, which gives you an easier understanding on how it works.
using System;
class test
{
static int Main(string[] argsin)
{
for (int i = 0; i < argsin.Length; i++ )
Console.WriteLine("Argument: {0}", argsin[i]);
Console.ReadLine();
return -1;
}
}
There's a special rule for C-like languages: You define it's scope using if(true) { ... } similar to If True Then ... End If, but if you only have one line, you can decide not to use brackets. Therefor the next line after the if or for[each] will be used for the scope.
The i++ does not end with a ; because it is within the declaration of the for.
Also, don't forget to have a look at the foreach loop.
If I rewrite your method with different formatting (but identical syntax), it may make things clearer:
static int Main(string[] argsin)
{
for (int i = 0; i < argsin.Length; i++)
{
Console.WriteLine("Argument: {0}", argsin[i]);
}
Console.ReadLine();
return -1;
}
Remember that c# doesn't use a line break for statement termination (unlike VB). The "third line" in your 'for' loop isn't actually a "line," it's just the third expression, and is terminated by the closing bracket.
The reason the loop continues rather than quitting is because (without squiggly brackets to indicate a statement block) the 'for' loop will only loop the single statement immediately following the loop - that is, the 'Console.WriteLine'. I'm guessing that you thought that the 'ReadLine' and 'return' statements would be part of the loop but, in C# syntax, that's not the case. (I added the bracess to my version to make the scope of the loop clearer).
I'll answer the part of your question...
for is a construct that has initializer, loop statement, and terminating condition.
So
for (X, Y, Z) { }
would be equivalent to
X;
while (Y)
{
// code
Z;
}
As for your question about not quiting the application - for () will bind to first NEXT statement, or statement BLOCK. In your case, you have only one line as a statement. If there would be more lines, you should write them encased in { and }.
Typical syntax for a for loop is:
for( int i = 0; i < argsin.Length; i++ )
{
//<CODE>
}
So you'd read it (in your mind) as: "With the temporary value 'i' starting at the value 0, while 'i' is less than 'argsin.Length', do '//' with i as the value, always ending with 'i++'"
A for loop just gets translated to:
{
int i = 0;
while( i < argsin.Lenth )
{
//<CODE>
i++;
}
}
(The extra surrounding braces are to say that 'i' goes out of scope and can no longer be used when the brace closes). Like any 'if' or 'while' statement the closing parenthesis provides the 'end-of-statement' "Character" (if you will) and so the semicolon is unnecessary. Earlier they are a must because you have to know where to end each statement.
[EDIT]
By the way: there's a little more to it than a straight translation. There are cases where you can include multiple initializations, and multiple 'at the end of each loop' instructions. Don't worry about those until you understand what's going on.
That is the basic of the for loop, in that loop, you declare that the starting value of integer i is zero and it should continue to loop until i is equal to the length of string[] argsin and increase the value of i on each iteration. Which means if the length of your argsin array is 5, the loop will
// first run
for(int i = 0;i<5;i++)
Console.WriteLine("Argument: {0}",argsin[0]);
// second run
for(int i = 1;i<5;i++)
Console.WriteLine("Argument: {0}",argsin[1]);
// third run
for(int i = 2;i<5;i++)
Console.WriteLine("Argument: {0}",argsin[2]);
// forth run
for(int i = 3;i<5;i++)
Console.WriteLine("Argument: {0}",argsin[3]);
// fifth run
for(int i = 4;i<5;i++)
Console.WriteLine("Argument: {0}",argsin[4]);
After 5 runs, i will be 5 and will not meet 5 < 5 and quit this loop and go on with the next statement.

Identifying last loop when using for each [duplicate]

This question already has answers here:
Foreach loop, determine which is the last iteration of the loop
(24 answers)
Closed 10 days ago.
I want to do something different with the last loop iteration when performing 'foreach' on an object. I'm using Ruby but the same goes for C#, Java etc.
list = ['A','B','C']
list.each{|i|
puts "Looping: "+i # if not last loop iteration
puts "Last one: "+i # if last loop iteration
}
The output desired is equivalent to:
Looping: 'A'
Looping: 'B'
Last one: 'C'
The obvious workaround is to migrate the code to a for loop using 'for i in 1..list.length', but the for each solution feels more graceful. What is the most graceful way to code a special case during a loop? Can it be done with foreach?
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(",");
}
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.
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
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]
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
}
You can define an eachwithlast method in your class to do the same as each on all elements but the last, but something else for the last:
class MyColl
def eachwithlast
for i in 0...(size-1)
yield(self[i], false)
end
yield(self[size-1], true)
end
end
Then you could call it like this (foo being an instance of MyColl or a subclass thereof):
foo.eachwithlast do |value, last|
if last
puts "Last one: "+value
else
puts "Looping: "+value
end
end
Edit: Following molf's suggestion:
class MyColl
def eachwithlast (defaultAction, lastAction)
for i in 0...(size-1)
defaultAction.call(self[i])
end
lastAction.call(self[size-1])
end
end
foo.eachwithlast(
lambda { |x| puts "looping "+x },
lambda { |x| puts "last "+x } )
C# 3.0 or newer
Firstly, I would write an extension method:
public static void ForEachEx<T>(this IEnumerable<T> s, Action<T, bool> act)
{
IEnumerator<T> curr = s.GetEnumerator();
if (curr.MoveNext())
{
bool last;
while (true)
{
T item = curr.Current;
last = !curr.MoveNext();
act(item, last);
if (last)
break;
}
}
}
Then using the new foreach is very simple:
int[] lData = new int[] { 1, 2, 3, 5, -1};
void Run()
{
lData.ForEachEx((el, last) =>
{
if (last)
Console.Write("last one: ");
Console.WriteLine(el);
});
}
You should use foreach only if you handle each one same. Use index based interation instead. Else you must add a different structure around the items, which you can use to differentiate the normal from last one in the foreach call (look at good Papers about the map reduced from google for the background: http://labs.google.com/papers/mapreduce.html, map == foreach, reduced == e.g. sum or filter).
Map has no knowledge about the structure (esp. which position a item is), it only transforms one item by item (no knowledge from one item can be used to transform an other!), but reduce can use a memory to for example count the position and handle the last item.
A common trick is to reverse the list and handle the first (which has now a known index = 0), and later apply reverse again. (Which is elegant but not fast ;) )
Foreach is elegant in that it has no concern for the number of items in a list and treats each element equally, I think your only solution will be using a for loop that either stops at itemcount-1 and then you present your last item outside of the loop or a conditional within the loop that handles that specific condition, i.e. if (i==itemcount) { ... } else { ... }
You could do something like that (C#) :
string previous = null;
foreach(string item in list)
{
if (previous != null)
Console.WriteLine("Looping : {0}", previous);
previous = item;
}
if (previous != null)
Console.WriteLine("Last one : {0}", previous);
Ruby also has each_index method:
list = ['A','B','C']
list.each_index{|i|
if i < list.size - 1
puts "Looping:"+list[i]
else
puts "Last one:"+list[i]
}
EDIT:
Or using each (corrected TomatoGG and Kirschstein solution):
list = ['A', 'B', 'C', 'A']
list.each { |i|
if (i.object_id != list.last.object_id)
puts "Looping:#{i}"
else
puts "Last one:#{i}"
end
}
Looping:A
Looping:B
Looping:C
Last one:A
Or
list = ['A', 'B', 'C', 'A']
list.each {|i|
i.object_id != list.last.object_id ? puts "Looping:#{i}" : puts "Last one:#{i}"
}
What you are trying to do seems just a little too advanced for the foreach-loop. However, you can use Iterators explicitly. For example, in Java, I would write this:
Collection<String> ss = Arrays.asList("A","B","C");
Iterator<String> it = ss.iterator();
while (it.hasNext()) {
String s = it.next();
if(it.hasNext())
System.out.println("Looping: " + s);
else
System.out.println("Last one: " + s);
}
If you're using a collection that exposes a Count property - an assumption made by many of the other answers, so I'll make it too - then you can do something like this using C# and LINQ:
foreach (var item in list.Select((x, i) => new { Val = x, Pos = i }))
{
Console.Write(item.Pos == (list.Count - 1) ? "Last one: " : "Looping: ");
Console.WriteLine(item.Val);
}
If we additionally assume that the items in the collection can be accessed directly by index - the currently accepted answer assumes this - then a plain for loop will be more elegant/readable than a foreach:
for (int i = 0; i < list.Count; i++)
{
Console.Write(i == (list.Count - 1) ? "Last one: " : "Looping: ");
Console.WriteLine(list[i]);
}
If the collection doesn't expose a Count property and can't be accessed by index then there isn't really any elegant way to do this, at least not in C#. A bug-fixed variation of Thomas Levesque's answer is probably as close as you'll get.
Here's the bug-fixed version of Thomas's answer:
string previous = null;
bool isFirst = true;
foreach (var item in list)
{
if (!isFirst)
{
Console.WriteLine("Looping: " + previous);
}
previous = item;
isFirst = false;
}
if (!isFirst)
{
Console.WriteLine("Last one: " + previous);
}
And here's how I would do it in C# if the collection doesn't expose a Count property and the items aren't directly accessible by index. (Notice that there's no foreach and the code isn't particularly succinct, but it will give decent performance over pretty much any enumerable collection.)
// i'm assuming the non-generic IEnumerable in this code
// wrap the enumerator in a "using" block if dealing with IEnumerable<T>
var e = list.GetEnumerator();
if (e.MoveNext())
{
var item = e.Current;
while (e.MoveNext())
{
Console.WriteLine("Looping: " + item);
item = e.Current;
}
Console.WriteLine("Last one: " + item);
}
At least in C# that's not possible without a regular for loop.
The enumerator of the collection decides whether a next elements exists (MoveNext method), the loop doesn't know about this.
I think I prefer kgiannakakis's solution, however you could always do something like this;
list = ['A','B','C']
list.each { |i|
if (i != list.last)
puts "Looping:#{i}"
else
puts "Last one:#{i}"
end
}
I notice a number of suggestions assume that you can find the last item in the list before beginning the loop, and then compare every item to this item. If you can do this efficiently, then the underlying data structure is likely a simple array. If that's the case, why bother with the foreach at all? Just write:
for (int x=0;x<list.size()-1;++x)
{
System.out.println("Looping: "+list.get(x));
}
System.out.println("Last one: "+list.get(list.size()-1));
If you cannot retrieve an item from an arbitrary position efficiently -- like it the underlying structure is a linked list -- then getting the last item probably involved a sequential search of the entire list. Depending on the size of the list, that may be a performance issue. If this is a frequently-executed function, you might want to consider using an array or ArrayList or comparable structure so you can do it this way.
Sounds to me like you're asking, "What's the best way to put a screw in using a hammer?", when of course the better question to ask is, "What's the correct tool to use to put in a screw?"
Would it be a viable solution for your case to just take the first/last elements out of your array before doing the "general" each run?
Like this:
list = ['A','B','C','D']
first = list.shift
last = list.pop
puts "First one: #{first}"
list.each{|i|
puts "Looping: "+i
}
puts "Last one: #{last}"
This problem can be solved in an elegant way using pattern matching in a functional programming language such as F#:
let rec printList (ls:string list) =
match ls with
| [last] -> "Last " + last
| head::rest -> "Looping " + head + "\n" + printList (rest)
| [] -> ""
I don't know how for-each loops works in other languages but java.
In java for-each uses the Iterable interface that is used by the for-each to get an Iterator and loop with it. Iterator has a method hasNext that you could use if you could see the iterator within the loop.
You can actually do the trick by enclosing an already obtained Iterator in an Iterable object so the for loop got what it needs and you can get a hasNext method inside the loop.
List<X> list = ...
final Iterator<X> it = list.iterator();
Iterable<X> itw = new Iterable<X>(){
public Iterator<X> iterator () {
return it;
}
}
for (X x: itw) {
doSomething(x);
if (!it.hasNext()) {
doSomethingElse(x);
}
}
You can create a class that wraps all this iterable and iterator stuff so the code looks like this:
IterableIterator<X> itt = new IterableIterator<X>(list);
for (X x: itit) {
doSomething(x);
if (!itit.hasNext()) {
doSomethingElse(x);
}
}
Similar to kgiannakakis's answer:
list.first(list.size - 1).each { |i| puts "Looping: " + i }
puts "Last one: " + list.last
How about this one? just learnt a little Ruby. hehehe
list.collect {|x|(x!=list.last ? "Looping:"+x:"Lastone:"+x) }.each{|i|puts i}
Remove the last one from the list and retain its avlue.
Spec spec = specs.Find(s=>s.Value == 'C');
if (spec != null)
{
specs.Remove(spec);
}
foreach(Spec spec in specs)
{
}
Another pattern that works, without having to rewrite the foreach loop:
var delayed = null;
foreach (var X in collection)
{
if (delayed != null)
{
puts("Looping");
// Use delayed
}
delayed = X;
}
puts("Last one");
// Use delayed
This way the compiler keeps the loop straight, iterators (including those without counts) work as expected, and the last one is separated out from the others.
I also use this pattern when I want something to happen in between iterations, but not after the last one. In that case, X is used normally, delayed refers to something else, and the usage of delayed is only at the loop beginning and nothing needs to be done after the loop ends.
Use join whenever possible.
Most often the delimiter is the same between all elements, just join them together with the corresponding function in your language.
Ruby example,
puts array.join(", ")
This should cover 99% of all cases, and if not split the array into head and tail.
Ruby example,
*head, tail = array
head.each { |each| put "looping: " << each }
puts "last element: " << tail
<hello> what are we thinking here?
public static void main(String[] args) {
// TODO Auto-generated method stub
String str = readIndex();
String comp[] = str.split("}");
StringBuffer sb = new StringBuffer();
for (String s : comp) {
sb.append(s);
sb.append("}\n");
}
System.out.println (sb.toString());
}
As a modeling notation, the influence of the OMT notation dominates (e. g., using rectangles for classes and objects). Though the Booch "cloud" notation was dropped, the Booch capability to specify lower-level design detail was embraced. The use case notation from Objectory and the component notation from Booch were integrated with the rest of the notation, but the semantic integration was relatively weak in UML 1.1, and was not really fixed until the UML 2.0 major revision.

Categories