next or break in a loop

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

next or break in a loop

Joseph Alotta
Greetings,

I am in need of a way to go to the end of a do loop.

myCollection do:  [ :item |

                (blah blah) ifTrue: “we found an item of the first type”
                 next item.

                (blah blah) ifTrue: “we found an item of the second type”
                 next item.
 
                (blah blah) ifTrue: “we found an item of the third type”
                next item.
 
                (blah blah) ifTrue: “we found an item of the fourth type”
                next item.

                (blah blah) ifTrue: “we found an item of the fifth type”

].


Some other languages have “break” or “next” or “goto LABEL” to skip the processing of the rest of the loop in case the item is found in the first test.

How do I implement this in Squeak?

Sincerely,

Joe.


PS.  This is not a homework project.



_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: next or break in a loop

Phil B
On Mon, 2016-05-09 at 12:51 -0500, Joseph Alotta wrote:

> Greetings,
>
> I am in need of a way to go to the end of a do loop.
>
> myCollection do:  [ :item |
>
>                 (blah blah) ifTrue: “we found an item of the first
> type”
>                  next item.
>
>                 (blah blah) ifTrue: “we found an item of the second
> type”
>                  next item.
>  
>                 (blah blah) ifTrue: “we found an item of the third
> type”
>                 next item.
>   
>                 (blah blah) ifTrue: “we found an item of the fourth
> type”
>                 next item.
>
>                 (blah blah) ifTrue: “we found an item of the fifth
> type”
>
> ].
>
>
> Some other languages have “break” or “next” or “goto LABEL” to skip
> the processing of the rest of the loop in case the item is found in
> the first test.
>
> How do I implement this in Squeak?
>

Smalltalk doesn't have a switch/case statement but there are a few ways
to implement the equivalent logic:

1) Nest the additional conditions inside ifFalse: statements:
cond1 ifTrue: [trueLogic...]
        ifFalse: [cond2 
                ifTrue: [trueLogic] 
                ifFalse: [otherLogic...]]
This is the simplest method but can get hard to follow/edit pretty
quickly re: brackets and formatting.  You could also add a 'done'
variable to avoid the nesting (and avoid multiple conditions from being
satisfied in a single pass):
done:=false.
cond1 ifTrue: [trueLogic.  done:=true].
(cond2 and: [done not]) ifTrue: [trueLogic.  done:=true].
(cond3 and:
[done not]) ifTrue: [trueLogic.  done:=true].
done ifFalse:
[otherLogic].

2) Store the conditional blocks as values in a dictionary:
switchBlock := Dictionary new
        at: condValue1 put: [block1];
        at: condValue2 put: [block2];
        at: condValue3 put: [block3];
        yourself.
then to evaluate it:
(switchBlock at: condValue) value

3) Implement a switch method and call it:
switchMethod: switchVal
        switchVal = cond1 ifTrue: [trueLogic.  ^ whatever].
        switchVal = cond2 ifTrue: [trueLogic.  ^ whatever].
        swit
chVal = cond3 ifTrue: [trueLogic.  ^ whatever].
        otherLogic

This is one area where I wish Smalltalk had nicer syntax / syntactic sugar for... any of the above is a bit clunky and you need it often enough where this can get tedious.

> Sincerely,
>
> Joe.
>
>
> PS.  This is not a homework project.
>
>
>
> _______________________________________________
> Beginners mailing list
> [hidden email]
> http://lists.squeakfoundation.org/mailman/listinfo/beginners
_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: next or break in a loop

Bert Freudenberg
On 09.05.2016, at 20:35, Phil (list) <[hidden email]> wrote:
>
> Smalltalk doesn't have a switch/case statement

True, but Squeak does:

        aValue caseOf: {
                [firstValue] -> [firstBlock].
                [secondValue] -> [secondBlock].
        } otherwise: [elseBlock]

- Bert -




_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners

smime.p7s (5K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: next or break in a loop

Andreas Wacknitz
In reply to this post by Joseph Alotta
Am 09.05.16 um 19:51 schrieb Joseph Alotta:

> Greetings,
>
> I am in need of a way to go to the end of a do loop.
>
> myCollection do:  [ :item |
>
>                  (blah blah) ifTrue: “we found an item of the first type”
>                   next item.
>
>                  (blah blah) ifTrue: “we found an item of the second type”
>                   next item.
>  
>                  (blah blah) ifTrue: “we found an item of the third type”
>                  next item.
>    
>                  (blah blah) ifTrue: “we found an item of the fourth type”
>                  next item.
>
>                  (blah blah) ifTrue: “we found an item of the fifth type”
>
> ].
>
>
> Some other languages have “break” or “next” or “goto LABEL” to skip the processing of the rest of the loop in case the item is found in the first test.
>
> How do I implement this in Squeak?
I don't have a good answer for your problem. Smalltalk offers a great
interface for iterating over collections, >>do: is not the only one.
Alas there is no-one I am aware of that supports what is needed here
(something like a split into different sub-collections).
 >>select: could be used to get all the items for one of your
conditions. Thus, for your problem you would need five select:-loops,
which is sub-optimal performance-wise.
Maybe your problem can be rephrased such that Smalltalk's collection
interface offers a better solution. Nevertheless, I suggest to take
a closer look at the remaining selectors like >>select:, >>reject:,
 >>collect, ...

Regards
Andreas


_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: next or break in a loop

Phil B
In reply to this post by Bert Freudenberg
On Mon, 2016-05-09 at 20:51 +0200, Bert Freudenberg wrote:

> On 09.05.2016, at 20:35, Phil (list) <[hidden email]> wrote:
> >
> >
> > Smalltalk doesn't have a switch/case statement
> True, but Squeak does:
>
> aValue caseOf: {
> [firstValue] -> [firstBlock].
> [secondValue] -> [secondBlock].
> } otherwise: [elseBlock]
>
> - Bert -
>

Hah... learn something new every day (I don't remember noticing that
method before.) This is definitely an improvement.

>
>
> _______________________________________________
> Beginners mailing list
> [hidden email]
> http://lists.squeakfoundation.org/mailman/listinfo/beginners
_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: next or break in a loop

Tobias Pape
In reply to this post by Joseph Alotta
Hi Joseph,

On 09.05.2016, at 19:51, Joseph Alotta <[hidden email]> wrote:

> Greetings,
>
> I am in need of a way to go to the end of a do loop.
>
> myCollection do:  [ :item |
>
>                (blah blah) ifTrue: “we found an item of the first type”
>                 next item.
>
>                (blah blah) ifTrue: “we found an item of the second type”
>                 next item.
>
>                (blah blah) ifTrue: “we found an item of the third type”
>                next item.
>
>                (blah blah) ifTrue: “we found an item of the fourth type”
>                next item.
>
>                (blah blah) ifTrue: “we found an item of the fifth type”
>
> ].

Can you go a little into detail?
Typically, I'd put whatever is to be done when you "know of what type" your items are into its Class,
relying on polymorphism.

For example, given you have ducks, cats, and dogs and want them to call, you'd do:

Dog>>call
  self sound: 'Waff Waff'.

Cat>>call
  self sound: 'Meow'.

Duck>>call
  self sound: 'Quak!'.


So you can use it like this:

{Dog new. Cat new. Dog new. Duck new. Duck new} do: [:animal |
  animal call].
"=> 'Waff Waff', 'Meow', 'Waff Waff', 'Quak!', 'Quak!'

What happens when you have a Centipede that does not call at all?

Well, let's assume the animals are organized all together in a common super class, Animal.

In Animal, we say

Animal>>call
  ^ self

to say a 'generic' animal does not do anything when calling.
We could do

Centipede>>call
  ^ self

or

Centipede>>call
  ^ super call

but that superfluous given Animal>>call.

So, what do we have now?

{Dog new. Cat new. Centipede new. Dog new. Duck new. Centipede new. Duck new} do: [:animal |
  animal call].
"=> 'Waff Waff', 'Meow', 'Waff Waff', 'Quak!', 'Quak!'


That way, no 'goto' or 'continue' is necessary.

Best regards
        -Tobias



_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: next or break in a loop

Joseph Alotta
I don’t think any of the solutions work for my case.

I want to evaluate several different variable for each step, make calculations and if all of the conditions are met, then skip to the next item, otherwise, do the next step of calculations.

The project is reading comma deliminated bank or credit card files, taking a column of data, counting various characters, and trying to determine what kind of data it is.  For example, a column of data with two slash characters and eight digits per line is likely to be a date field.  A column of data with more than 3 letter characters and a percentage of digits and a percentage of hash signs is likely to be a payee field.  A column of data with no spaces, no digits, no special characters is likely to be a type of transaction field.  A column of data with one period per item, and only digits or a minus sign is  likely to be a amount field, and a column of data with a high percentage of zero length items and the rest having C or K and a pound sign and four or more digits is likely to be a check number field.

I am doing a lot of tests for each field and I don’t think the switch is a good fit.

Sincerely,

Joe.





_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: next or break in a loop

Andreas Wacknitz
Am 09.05.16 um 23:00 schrieb Joseph Alotta:
> I don’t think any of the solutions work for my case.
>
> I want to evaluate several different variable for each step, make calculations and if all of the conditions are met, then skip to the next item, otherwise, do the next step of calculations.
>
> The project is reading comma deliminated bank or credit card files, taking a column of data, counting various characters, and trying to determine what kind of data it is.  For example, a column of data with two slash characters and eight digits per line is likely to be a date field.  A column of data with more than 3 letter characters and a percentage of digits and a percentage of hash signs is likely to be a payee field.  A column of data with no spaces, no digits, no special characters is likely to be a type of transaction field.  A column of data with one period per item, and only digits or a minus sign is  likely to be a amount field, and a column of data with a high percentage of zero length items and the rest having C or K and a pound sign and four or more digits is likely to be a check number field.
>
> I am doing a lot of tests for each field and I don’t think the switch is a good fit.
>
What you probably need is a parser for the things you want to detect and
consume. SmaCC or PetitParser comes to my mind...

Regards
Andreas

_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: next or break in a loop

Bert Freudenberg
In reply to this post by Joseph Alotta

> On 09.05.2016, at 23:00, Joseph Alotta <[hidden email]> wrote:
>
> I don’t think any of the solutions work for my case.
>
> I want to evaluate several different variable for each step, make calculations and if all of the conditions are met, then skip to the next item, otherwise, do the next step of calculations.
>
> The project is reading comma deliminated bank or credit card files, taking a column of data, counting various characters, and trying to determine what kind of data it is.  For example, a column of data with two slash characters and eight digits per line is likely to be a date field.  A column of data with more than 3 letter characters and a percentage of digits and a percentage of hash signs is likely to be a payee field.  A column of data with no spaces, no digits, no special characters is likely to be a type of transaction field.  A column of data with one period per item, and only digits or a minus sign is  likely to be a amount field, and a column of data with a high percentage of zero length items and the rest having C or K and a pound sign and four or more digits is likely to be a check number field.
>
> I am doing a lot of tests for each field and I don’t think the switch is a good fit.

Sounds like my first suggestion would work then. Create a method “processColumn:” that tries to match each pattern and, if successful, reads the data and returns.

This should work, but you would have to put a lot of code into one single method, which is bad style. Better to have a set of parsing methods (e.g. parseAsDate:, parseAsPayee: etc) that would return true if they succeeded, and if not, the next one would be tried.

And instead of having a couple of methods you could have a couple of parser classes that each would try to parse the item. You would put the parsers in a collection and try each of them until one successfully parsed. This would probably be the most object-oriented solution.

- Bert -




_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners

smime.p7s (5K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

next or break in a loop

Louis LaBrunda
In reply to this post by Joseph Alotta
Hi Joe,

You can map your collection to a stream and then use the stream methods to traverse the
collection.

        stream := ReadStream on: myCollection.
        [stream atEnd] whileFalse: [:item |
                item := stream next.
"I'm not sure upToEnd is the right method here but it is close.  Look around, I'm sure you will
find what you need."
                item doSomeWork.
                (when you think you are done with item) ifTrue: [stream upToEnd].
        ].

Lou

On Mon, 9 May 2016 16:00:58 -0500, Joseph Alotta <[hidden email]> wrote:

>I don’t think any of the solutions work for my case.
>
>I want to evaluate several different variable for each step, make calculations and if all of the conditions are met, then skip to the next item, otherwise, do the next step of calculations.
>
>The project is reading comma deliminated bank or credit card files, taking a column of data, counting various characters, and trying to determine what kind of data it is.  For example, a column of data with two slash characters and eight digits per line is likely to be a date field.  A column of data with more than 3 letter characters and a percentage of digits and a percentage of hash signs is likely to be a payee field.  A column of data with no spaces, no digits, no special characters is likely to be a type of transaction field.  A column of data with one period per item, and only digits or a minus sign is  likely to be a amount field, and a column of data with a high percentage of zero length items and the rest having C or K and a pound sign and four or more digits is likely to be a check number field.
>
>I am doing a lot of tests for each field and I don’t think the switch is a good fit.
>
>Sincerely,
>
>Joe.
--
Louis LaBrunda
Keystone Software Corp.
SkypeMe callto://PhotonDemon

_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: next or break in a loop

Phil B
In reply to this post by Joseph Alotta
On Mon, 2016-05-09 at 16:00 -0500, Joseph Alotta wrote:
> The project is reading comma deliminated bank or credit card files,

It sounds like you're processing something along the lines of
Quicken/MS Money data files that you download from your bank / credit
card company.  If that's the case, Andreas' solution re: a parser would
be the way I'd go.

_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: next or break in a loop

Joseph Alotta
In reply to this post by Louis LaBrunda
Lou,

I was trying to use the ReadStream, but the issue is to get execution to go back to the top.  If I send the upToEnd message, it still executes from the same line and goes through the rest of the tests.


Sincerely,

Joe.



> On May 9, 2016, at 3:56 PM, Louis LaBrunda [via Smalltalk] <[hidden email]> wrote:
>
> Hi Joe,
>
> You can map your collection to a stream and then use the stream methods to traverse the
> collection.
>
>         stream := ReadStream on: myCollection.
>         [stream atEnd] whileFalse: [:item |
>                 item := stream next.
> "I'm not sure upToEnd is the right method here but it is close.  Look around, I'm sure you will
> find what you need."
>                 item doSomeWork.
>                 (when you think you are done with item) ifTrue: [stream upToEnd].
>         ].
>
> Lou
>
> On Mon, 9 May 2016 16:00:58 -0500, Joseph Alotta <[hidden email]> wrote:
>
> >I don’t think any of the solutions work for my case.
> >
> >I want to evaluate several different variable for each step, make calculations and if all of the conditions are met, then skip to the next item, otherwise, do the next step of calculations.
> >
> >The project is reading comma deliminated bank or credit card files, taking a column of data, counting various characters, and trying to determine what kind of data it is.  For example, a column of data with two slash characters and eight digits per line is likely to be a date field.  A column of data with more than 3 letter characters and a percentage of digits and a percentage of hash signs is likely to be a payee field.  A column of data with no spaces, no digits, no special characters is likely to be a type of transaction field.  A column of data with one period per item, and only digits or a minus sign is  likely to be a amount field, and a column of data with a high percentage of zero length items and the rest having C or K and a pound sign and four or more digits is likely to be a check number field.
> >
> >I am doing a lot of tests for each field and I don’t think the switch is a good fit.
> >
> >Sincerely,
> >
> >Joe.
> --
> Louis LaBrunda
> Keystone Software Corp.
> SkypeMe callto://PhotonDemon
>
> _______________________________________________
> Beginners mailing list
> [hidden email]
> http://lists.squeakfoundation.org/mailman/listinfo/beginners
>
>
> If you reply to this email, your message will be added to the discussion below:
> http://forum.world.st/next-or-break-in-a-loop-tp4894095p4894128.html
> To start a new topic under Squeak - Beginners, email [hidden email]
> To unsubscribe from Squeak - Beginners, click here.
> NAML

Reply | Threaded
Open this post in threaded view
|

next or break in a loop

Louis LaBrunda
Joe,

At each test for the type of data you can also test to see if you found type, something like
this:

        stream := ReadStream on: myCollection.
        [stream atEnd] whileFalse: [:item | | notFound |
                item := stream next.
                notFound := true.
          (notFound and: [your column test1]) ifTrue: [notFound := false. stream upToEnd].
                (notFound and: [your column test2]) ifTrue: [notFound := false. stream upToEnd].
                (notFound and: [your column test3]) ifTrue: [notFound := false. stream upToEnd].
        ].

Not pretty but it should work.  You should also look into the #caseOf: method Bert suggested. I
have my own Case class in VA Smalltalk that I expect is similar but I'm not familiar with
#caseOf:, so you should look it up.  I expect it will make the code a little cleaner.

Lou

On Tue, 10 May 2016 08:57:03 -0700 (PDT), Joseph Alotta <[hidden email]> wrote:

>Lou,
>
>I was trying to use the ReadStream, but the issue is to get execution to go back to the top.  If I send the upToEnd message, it still executes from the same line and goes through the rest of the tests.
>
>
>Sincerely,
>
>Joe.
>
>
>
>> On May 9, 2016, at 3:56 PM, Louis LaBrunda [via Smalltalk] <[hidden email]> wrote:
>>
>> Hi Joe,
>>
>> You can map your collection to a stream and then use the stream methods to traverse the
>> collection.
>>
>>         stream := ReadStream on: myCollection.
>>         [stream atEnd] whileFalse: [:item |
>>                 item := stream next.
>> "I'm not sure upToEnd is the right method here but it is close.  Look around, I'm sure you will
>> find what you need."
>>                 item doSomeWork.
>>                 (when you think you are done with item) ifTrue: [stream upToEnd].
>>         ].
>>
>> Lou
>>
>> On Mon, 9 May 2016 16:00:58 -0500, Joseph Alotta <[hidden email]> wrote:
>>
>> >I don?t think any of the solutions work for my case.
>> >
>> >I want to evaluate several different variable for each step, make calculations and if all of the conditions are met, then skip to the next item, otherwise, do the next step of calculations.
>> >
>> >The project is reading comma deliminated bank or credit card files, taking a column of data, counting various characters, and trying to determine what kind of data it is.  For example, a column of data with two slash characters and eight digits per line is likely to be a date field.  A column of data with more than 3 letter characters and a percentage of digits and a percentage of hash signs is likely to be a payee field.  A column of data with no spaces, no digits, no special characters is likely to be a type of transaction field.  A column of data with one period per item, and only digits or a minus sign is  likely to be a amount field, and a column of data with a high percentage of zero length items and the rest having C or K and a pound sign and four or more digits is likely to be a check number field.
>> >
>> >I am doing a lot of tests for each field and I don?t think the switch is a good fit.
>> >
>> >Sincerely,
>> >
>> >Joe.
>> --
>> Louis LaBrunda
>> Keystone Software Corp.
>> SkypeMe callto://PhotonDemon
>>
>> _______________________________________________
>> Beginners mailing list
>> [hidden email]
>> http://lists.squeakfoundation.org/mailman/listinfo/beginners
>>
>>
>> If you reply to this email, your message will be added to the discussion below:
>> http://forum.world.st/next-or-break-in-a-loop-tp4894095p4894128.html
>> To start a new topic under Squeak - Beginners, email [hidden email]
>> To unsubscribe from Squeak - Beginners, click here.
>> NAML
--
Louis LaBrunda
Keystone Software Corp.
SkypeMe callto://PhotonDemon

_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: next or break in a loop

Joseph Alotta

> On May 10, 2016, at 12:03 PM, Louis LaBrunda [via Smalltalk] <[hidden email]> wrote:
>
> Joe,
>
> At each test for the type of data you can also test to see if you found type, something like
> this:
>
>         stream := ReadStream on: myCollection.
>         [stream atEnd] whileFalse: [:item | | notFound |
>                 item := stream next.
>                 notFound := true.
>           (notFound and: [your column test1]) ifTrue: [notFound := false. stream upToEnd].
>                 (notFound and: [your column test2]) ifTrue: [notFound := false. stream upToEnd].
>                 (notFound and: [your column test3]) ifTrue: [notFound := false. stream upToEnd].
>         ].
>
> Not pretty but it should work.

I added a flag and set it as one of the conditions.

Also, to make reading simpler, I stacked all the booleans.

bool := bool and: (condition).
bool := bool and: (another condition).

It is not pretty, but it avoids endless seas of parentheses.

Sincerely,

Joe.