digitalmars.D.learn - foreach annoyance
- Regan Heath (38/38) Aug 04 2005 Simple question.
- Derek Parnell (13/25) Aug 04 2005 I know this is not a real fast way to do it, but I have been know to do ...
- jicman (29/66) Aug 04 2005 I know, this is NOT what you want, but this is the best way to tell, any...
- Regan Heath (5/17) Aug 04 2005 In this code ii is string.length-1 if it finds nothing, or matches the
- Ben Hinkle (26/35) Aug 04 2005 Another option is to make foreach return the value of the opApply (or th...
- AJG (9/35) Aug 04 2005 Fantastic! This would be simply awesome. It would pave the way for the
- Ben Hinkle (3/7) Aug 04 2005 Holy smokes. I just read through the GNU C extension list. Those guys ma...
- AJG (15/22) Aug 05 2005 Yes indeed. When I started using GNU C (and the exts) I became spoiled f...
- Ilya Zaitseff (3/43) Aug 08 2005 How about foreach...else statement? I think it is an elegant solution.
- Regan Heath (6/55) Aug 08 2005 To me 'else' implies "if there is nothing in the container" whereas I wa...
- AJG (8/64) Aug 08 2005 No, I agree. My suggestion suggestion a while ago interpreted it just li...
- Derek Parnell (31/35) Aug 08 2005 This would be useful, as it saves me declaring a loop index just for
- AJG (7/14) Aug 08 2005 Then, by all means, vote for it*:
- Burton Radons (12/35) Aug 04 2005 I've found that this problem is symptomatic of over-complex control flow...
- Regan Heath (22/53) Aug 04 2005 Ok, can you give me a quick example?
- John Demme (14/19) Aug 04 2005 import std.stdio;
- AJG (4/15) Aug 04 2005 I'm guessing you wanna throw a return in there. Otherwise the "not found...
- John Demme (2/22) Aug 04 2005
Simple question. Does anyone else find themselves with this problem? //contrived example, actual values/data not important char[] string = "abcdefgh"; foreach(char c; string) { if (c == 'e') break; } //at this point I'd like to do something if the item wasn't found.. how can I tell? I can tell when using a for loop: int i; for(i = 0; i < string.length; i++) { if (string[i] == 'e') break; } if (i == string.length) {} //not found But I thought the idea was to use foreach so that I can change the container type at a later date with no other changes required. Of course, I could add 'i' to the foreach in the same way, eg. int i = 0; foreach(char c; string) { if (c == 'e') break; i++; } if (i == string.length) {} //not found But it would be nice if there was a more elegant solution. Something like: foreach(char c; string) { if(c == 'e') break; } overflow { //not found } However "overflow" doesn't seem like quite the right term. Regan
Aug 04 2005
On Fri, 05 Aug 2005 00:27:48 +1200, Regan Heath wrote:Simple question. Does anyone else find themselves with this problem? //contrived example, actual values/data not important char[] string = "abcdefgh"; foreach(char c; string) { if (c == 'e') break; } //at this point I'd like to do something if the item wasn't found.. how can I tell?I know this is not a real fast way to do it, but I have been know to do ... char[] string = "abcdefgh"; foreach(int i, char c; string) { if (c == 'e') break; if (i == string.length-1) ... } But in most cases this is too much of an overhead. -- Derek Parnell Melbourne, Australia 4/08/2005 10:59:11 PM
Aug 04 2005
Regan Heath says...Simple question. Does anyone else find themselves with this problem? //contrived example, actual values/data not important char[] string = "abcdefgh"; foreach(char c; string) { if (c == 'e') break; } //at this point I'd like to do something if the item wasn't found.. how can I tell? I can tell when using a for loop: int i; for(i = 0; i < string.length; i++) { if (string[i] == 'e') break; } if (i == string.length) {} //not found But I thought the idea was to use foreach so that I can change the container type at a later date with no other changes required. Of course, I could add 'i' to the foreach in the same way, eg. int i = 0; foreach(char c; string) { if (c == 'e') break; i++; } if (i == string.length) {} //not found But it would be nice if there was a more elegant solution. Something like: foreach(char c; string) { if(c == 'e') break; } overflow { //not found } However "overflow" doesn't seem like quite the right term.I know, this is NOT what you want, but this is the best way to tell, anyway. Using the good ole found variable. :-) |bit found = false; |foreach (char c; string) |{ | if(c == 'e') | { | found = true; | break; | } |} | |if (found) |{ |// found it |} However, there is another way you could do this: |int ii; |foreach (int i; char c; string) |{ | ii = i; | if(c == 'e') | break; |} After the loop is processed, ii will have the value that i had at the time of encounter or loop completion. just a thought... josé
Aug 04 2005
On Thu, 4 Aug 2005 13:26:31 +0000 (UTC), jicman <jicman_member pathlink.com> wrote:However, there is another way you could do this: |int ii; |foreach (int i; char c; string) |{ | ii = i; | if(c == 'e') | break; |} After the loop is processed, ii will have the value that i had at the time of encounter or loop completion. just a thought...In this code ii is string.length-1 if it finds nothing, or matches the last element. Regan
Aug 04 2005
But it would be nice if there was a more elegant solution. Something like: foreach(char c; string) { if(c == 'e') break; } overflow { //not found }Another option is to make foreach return the value of the opApply (or the builtin loop if there is no opApply) and turn foreach into an expression instead of a statement. So for example int found = foreach(char c; string){ if (c == 'e') break; }; if (found) { // found 'e' in string } else { //. not found case } Note making foreach an expression would break existing code since the trailing ; would be needed to turn the expression into a statement. It also might be confusing that people might think they could have "return" statements in the foreach body instead of "break". People would also probably want to return values from the foreach like the index at the break. Given those problems if making foreach an expression is too wacky the result can be stored in an implicit variable _foreachAborted or something: foreach(char c; string){ if (c == 'e') break; } if (_foreachAborted) { // found 'e' in string } else { //. not found case }
Aug 04 2005
Hi Ben,Another option is to make foreach return the value of the opApply (or the builtin loop if there is no opApply) and turn foreach into an expression instead of a statement. So for example int found = foreach(char c; string){ if (c == 'e') break; }; if (found) { // found 'e' in string } else { //. not found case }Fantastic! This would be simply awesome. It would pave the way for the expressionisation of all constructs just like current GNU C extensions allow. A vote for expression-foreach is a vote for the future.Note making foreach an expression would break existing code since the trailing ; would be needed to turn the expression into a statement. It also might be confusing that people might think they could have "return" statements in the foreach body instead of "break". People would also probably want to return values from the foreach like the index at the break.Yeah, the trailing ; could break things, but it would be well worth it. Alternatively, we could have both versions (expression foreach w/ the ; and regular foreach w/o ;. Then, regular foreach could be deprecated over time).Given those problems if making foreach an expression is too wacky the result can be stored in an implicit variable _foreachAborted or something: foreach(char c; string){ if (c == 'e') break; } if (_foreachAborted) { // found 'e' in string } else { //. not found case }On the other hand, this part I don't like that much. --AJG.
Aug 04 2005
Fantastic! This would be simply awesome. It would pave the way for the expressionisation of all constructs just like current GNU C extensions allow. A vote for expression-foreach is a vote for the future.Holy smokes. I just read through the GNU C extension list. Those guys make Willy Wonka look like an amateur :P I wonder what feedback they've gotten about some of those ideas.
Aug 04 2005
Hi,Yes indeed. When I started using GNU C (and the exts) I became spoiled for life. Going back to even C99 is a painful proposition.Fantastic! This would be simply awesome. It would pave the way for the expressionisation of all constructs just like current GNU C extensions allow. A vote for expression-foreach is a vote for the future.Holy smokes. I just read through the GNU C extension list. Those guys make Willy Wonka look like an amateur :PI wonder what feedback they've gotten about some of those ideas.I suspect it's been mostly positive for two reasons: a) They are all toggleable (specifically or all at once). So you can use them or completely ignore them. You can also force ANSI/C89/99 compatibility if you want. b) They keep churning 'em out. ;) I really, really hope Walter takes a look at them and invests time in implementing the best of them in D. A particularly easy one I suggested a while back was omitting the middle operand in the ternary operator. Expression-foreach would be a great step in that direction, so I definitely support it. Cheers, --AJG.
Aug 05 2005
How about foreach...else statement? I think it is an elegant solution. On Fri, 05 Aug 2005 00:57:32 +1100, Ben Hinkle <bhinkle mathworks.com> wrote:But it would be nice if there was a more elegant solution. Something like: foreach(char c; string) { if(c == 'e') break; } overflow { //not found }Another option is to make foreach return the value of the opApply (or the builtin loop if there is no opApply) and turn foreach into an expression instead of a statement. So for example int found = foreach(char c; string){ if (c == 'e') break; }; if (found) { // found 'e' in string } else { //. not found case } Note making foreach an expression would break existing code since the trailing ; would be needed to turn the expression into a statement. It also might be confusing that people might think they could have "return" statements in the foreach body instead of "break". People would also probably want to return values from the foreach like the index at the break. Given those problems if making foreach an expression is too wacky the result can be stored in an implicit variable _foreachAborted or something: foreach(char c; string){ if (c == 'e') break; } if (_foreachAborted) { // found 'e' in string } else { //. not found case }
Aug 08 2005
On Tue, 09 Aug 2005 13:30:23 +1100, Ilya Zaitseff <sark7 mail333.com> wrote:How about foreach...else statement? I think it is an elegant solution.To me 'else' implies "if there is nothing in the container" whereas I want "if you reach the end of the container", having else do what I want would be confusing.. or maybe just to me :) ReganOn Fri, 05 Aug 2005 00:57:32 +1100, Ben Hinkle <bhinkle mathworks.com> wrote:But it would be nice if there was a more elegant solution. Something like: foreach(char c; string) { if(c == 'e') break; } overflow { //not found }Another option is to make foreach return the value of the opApply (or the builtin loop if there is no opApply) and turn foreach into an expression instead of a statement. So for example int found = foreach(char c; string){ if (c == 'e') break; }; if (found) { // found 'e' in string } else { //. not found case } Note making foreach an expression would break existing code since the trailing ; would be needed to turn the expression into a statement. It also might be confusing that people might think they could have "return" statements in the foreach body instead of "break". People would also probably want to return values from the foreach like the index at the break. Given those problems if making foreach an expression is too wacky the result can be stored in an implicit variable _foreachAborted or something: foreach(char c; string){ if (c == 'e') break; } if (_foreachAborted) { // found 'e' in string } else { //. not found case }
Aug 08 2005
In article <opsu7ymedr23k2f5 nrage.netwin.co.nz>, Regan Heath says...On Tue, 09 Aug 2005 13:30:23 +1100, Ilya Zaitseff <sark7 mail333.com> wrote:No, I agree. My suggestion suggestion a while ago interpreted it just like that. foreach (item; array) // Array not empty. else // Array is empty. Cheers, --AJG.How about foreach...else statement? I think it is an elegant solution.To me 'else' implies "if there is nothing in the container" whereas I want "if you reach the end of the container", having else do what I want would be confusing.. or maybe just to me :)ReganOn Fri, 05 Aug 2005 00:57:32 +1100, Ben Hinkle <bhinkle mathworks.com> wrote:But it would be nice if there was a more elegant solution. Something like: foreach(char c; string) { if(c == 'e') break; } overflow { //not found }Another option is to make foreach return the value of the opApply (or the builtin loop if there is no opApply) and turn foreach into an expression instead of a statement. So for example int found = foreach(char c; string){ if (c == 'e') break; }; if (found) { // found 'e' in string } else { //. not found case } Note making foreach an expression would break existing code since the trailing ; would be needed to turn the expression into a statement. It also might be confusing that people might think they could have "return" statements in the foreach body instead of "break". People would also probably want to return values from the foreach like the index at the break. Given those problems if making foreach an expression is too wacky the result can be stored in an implicit variable _foreachAborted or something: foreach(char c; string){ if (c == 'e') break; } if (_foreachAborted) { // found 'e' in string } else { //. not found case }
Aug 08 2005
On Tue, 9 Aug 2005 04:15:38 +0000 (UTC), AJG wrote:foreach (item; array) // Array not empty. else // Array is empty.This would be useful, as it saves me declaring a loop index just for checking the first or last iteration, which is something I do frequently, ... foreach( <itemdecl>; <arrayref> ) on first <statement> // First iteration only on last <statement> // Final iteration only else <statement> // Only when there are zero iterations Example: foreach( CustRec c; CustomerList ) on first { Lineno = 0; Totals = 0; Pageno = 0; InitializeReport(); } Lineno++; GenPageHeading(Lineno, Pageno); GenDetailLine(Lineno, c, Totals); on last { GenFooter(Totals); CloseReport(); } else Msg("No customers on file"); Not a big thing, just a nice-to-have. -- Derek Melbourne, Australia 9/08/2005 2:28:36 PM
Aug 08 2005
Hi,Then, by all means, vote for it*: http://www.all-technology.com/eigenpolls/dwishlist/ * Although there hasn't been shown a positive correlation between the D wishlist and the D language. It functions more like a salve. ;) Cheers, --AJG.foreach (item; array) // Array not empty. else // Array is empty.This would be useful, as it saves me declaring a loop index just for checking the first or last iteration, which is something I do frequently, Not a big thing, just a nice-to-have.
Aug 08 2005
Regan Heath wrote:Simple question. Does anyone else find themselves with this problem? //contrived example, actual values/data not important char[] string = "abcdefgh"; foreach(char c; string) { if (c == 'e') break; } //at this point I'd like to do something if the item wasn't found.. how can I tell?I've found that this problem is symptomatic of over-complex control flow and should be delegated into a function (inner or outer) which tells you whether it found any entries and possibly acts on found entries if it can handle more than one. A method which goes along this path will become harder and harder to manipulate easily. Inner functions aren't just for doing a task more than once; they also act as self-documentation and control flow, reducing the core function to a series of modular parts to manipulate at will. This reminds me that I need to barge in on Parcel code and do some refactoring, I even use goto a couple times.I can tell when using a for loop: int i; for(i = 0; i < string.length; i++) { if (string[i] == 'e') break; } if (i == string.length) {} //not found But I thought the idea was to use foreach so that I can change the container type at a later date with no other changes required.It's no substitute for interfaces or templating.
Aug 04 2005
On Thu, 04 Aug 2005 08:23:29 -0700, Burton Radons <burton-radons smocky.com> wrote:Regan Heath wrote:Ok, can you give me a quick example? We're you thinking... void func() { char[] string = "abcdefg"; bool findItem(char item) { foreach(char c; string) { if (c == item) return true; } return false; } if (!findItem('e')) { } ..etc.. }Simple question. Does anyone else find themselves with this problem? //contrived example, actual values/data not important char[] string = "abcdefgh"; foreach(char c; string) { if (c == 'e') break; } //at this point I'd like to do something if the item wasn't found.. how can I tell?I've found that this problem is symptomatic of over-complex control flow and should be delegated into a function (inner or outer) which tells you whether it found any entries and possibly acts on found entries if it can handle more than one. A method which goes along this path will become harder and harder to manipulate easily. Inner functions aren't just for doing a task more than once; they also act as self-documentation and control flow, reducing the core function to a series of modular parts to manipulate at will. This reminds me that I need to barge in on Parcel code and do some refactoring, I even use goto a couple times.I thought the idea was that foreach was a template for iterating over a container. ReganI can tell when using a for loop: int i; for(i = 0; i < string.length; i++) { if (string[i] == 'e') break; } if (i == string.length) {} //not found But I thought the idea was to use foreach so that I can change the container type at a later date with no other changes required.It's no substitute for interfaces or templating.
Aug 04 2005
import std.stdio; void main() { char[] string = "abcdfgh"; foreach(char c; string) { if (c == 'e') goto found; } writefln("not found"); found: writefln("done"); } Hehe.. Might just be an acceptable use of "goto". Doesn't require the use of an extra variable, or an extra operator within the loop. On Fri, 2005-08-05 at 00:27 +1200, Regan Heath wrote:char[] string = "abcdefgh"; foreach(char c; string) { if (c == 'e') break; }
Aug 04 2005
Hi,import std.stdio; void main() { char[] string = "abcdfgh"; foreach(char c; string) { if (c == 'e') goto found; } writefln("not found"); found: writefln("done"); }I'm guessing you wanna throw a return in there. Otherwise the "not found" case also reaches the "found" case. No? --AJG.
Aug 04 2005
I dunno what the poster's intent was. On Fri, 2005-08-05 at 00:05 +0000, AJG wrote:Hi,import std.stdio; void main() { char[] string = "abcdfgh"; foreach(char c; string) { if (c == 'e') goto found; } writefln("not found"); found: writefln("done"); }I'm guessing you wanna throw a return in there. Otherwise the "not found" case also reaches the "found" case. No? --AJG.
Aug 04 2005