Is it possible to exit in 1 command, from two levels of nesting? That is, let us say I have this code:
foreach l { 1 2 3 4 } {
foreach k { 3 4 5 6 } {
if { $k > 4 } {
break2
} else {
puts "$k $l"
}
}
What that I would like to see output is:
1 3
1 4
The question is, how can one code the break2 (if possible)?.I do not know of such "feature" in any language, other than wrapping this in a proc, and using return to stop the proc, which is more of a hack than proper language constructThanks.
It's not possible to do it directly; the break machinery doesn't have anything to trace up to anything other than the nearest looping context.
The easiest way of handling this is to use try in 8.6 and a custom exception code (i.e., any value from 5 upwards).
foreach a {b c} {
puts "a=$a; to show that this is not stopping the outermost loop"
try {
foreach l { 1 2 3 4 } {
foreach k { 3 4 5 6 } {
if { $k > 4 } {
# Generating a custom exception code is a bit messy
return -level 0 -code 5
}
puts "$k $l"
}
}
} on 5 {} {
# Do nothing here; we've broken out
}
}
Running that gives this output:
a=b; to show that this is not stopping the outermost loop
3 1
4 1
a=c; to show that this is not stopping the outermost loop
3 1
4 1
But it's pretty messy to do this; the best approach is typically to refactor your code so that you can just return ordinarily to end the loop. Using apply might make this easier:
foreach a {b c} {
puts "a=$a; to show that this is not stopping the outermost loop"
apply {{} {
foreach l { 1 2 3 4 } {
foreach k { 3 4 5 6 } {
if { $k > 4 } {
return
}
puts "$k $l"
}
}
}}
}
The downside of using apply is that it is a different variable context and has quite a bit more overhead (because of all the stack frame management). Still, the variable context thing can be worked around using upvar if you're careful.
It's possible in Tcl ≥ 8.5:
foreach l { 1 2 3 4 } {
foreach k { 3 4 5 6 } {
if {$k > 4} {
return -code break -level 2
} else {
puts "$k $l"
}
}
}
That return -code break -level 2 works like "make the enclosing command two levels up the stack return as if it has called break".
The return command manual page.
Related
When using foreach in TCL to loop through a list it is desired to have a running number of the index of the current object. A way I have done this before is to maintain an extra counter variable.
set ct 0
foreach x $list {
puts "Items is $x index is $ct"
incr ct
}
One could use lsreach to retrieve the index but that's compute intensive and could be problematic with double occurrences.
Wondering if there is streamlined sleek-looking way of maintaining index information during a loop.
Pseudocode :
foreach x $list {
puts "Items is $x index is [foreach_index $x]"
}
Your feedback is appreciated.
UPDATE:
Run time tests with the provided answers:
Peter Lewerin : 86098.8 microseconds per iteration
Gert : 91057.4 microseconds per iteration
David B : 115860.0 microseconds per iteration
Loop through list with 100k random strings 80char long.
The loop proc is fastest, but hard to read.
While the control structure definitions in other languages are the law, in Tcl they're more like a set of guidelines.
proc foreachWithIndex {indexVar args} {
upvar 1 $indexVar var
set var 0
uplevel 1 [list foreach {*}[lrange $args 0 end-1] "[lindex $args end];incr $indexVar"]
}
foreachWithIndex x v {a b c} {puts "$x: $v"}
But I suggest using for instead. Radical language modifications are fun and occasionally useful, but if I had an Imperial credit for every such clever construct I ended up throwing away later I could build my own Death Star and still have money to put a grating over the exhaust port.
Your method of using incr with a counter works ok. This also works:
for { set i 0 } { $i < [llength $list] } { incr i } {
set x [lindex $list $i]
puts "Items is $x index is $i"
}
Another advantage of doing it this way is that you can modify the list while you are iterating. Let's say you want to remove all items with the value "bad" from a list.
set values { 1 2 3 bad 4 bad bad 5 }
for { set i 0 } { $i < [llength $values] } { incr i } {
if { [lindex $values $i] eq "bad" } {
set values [lreplace $values $i $i]
incr i -1
}
}
puts $values
I have written a function which currently displays all of the prime numbers under 1000.
I can keep making 1000 bigger to generate more numbers, but I do not know how to make it keep going on forever once run.
func generatePrimes() {
let numbers = 2...1000
for n in numbers {
var prime = true
for i in 2..<n {
if n % i == 0 {
prime = false
break
}
}
if prime == true {
print(n)
}
}
}
You could use a while loop with the argument being true. That way, the loop would never end.
func generatePrimes() {
var n = 2
while true {
var prime = true
for i in 2..<n {
if n % i == 0 {
prime = false
break
}
}
if prime == true {
print(n)
}
n += 1
}
}
Note that we use a variable (n) and increment (add 1 to it) on each iteration of the while loop.
If you want it to end when it hits some n, you can have a conditional that checks against n and break's out of the loop:
var n = 2
while true {
if n == 1000 {
break
}
n += 1
}
The above code will stop execution when n hits 1000 and will not print anything for that case.
Use a while loop instead of for loop. It can also be done with a for loop, but for loop is preferred when you know the number or range of the iterations you are performing. If you're using a while loop you just have to set the condition for the loop, in this case you need to specify the condition as true since you want the loop to run forever.
Just replace your for loop in your code with while. It should look something like this
while(true)
{
if n % i == 0 {
prime = false
break
}
}
You also can build an unconditional infinite loop using do {} block and continue statement.
AGAIN:
do {
print("step...")
continue AGAIN
}
func generatePrimes() {
var prime = true
let numbers = 2...1000
for n in numbers {
prime = true
if n == 2 || n == 3 {
print(n)
} else {
for i in 2..<n-1 {
if n % i == 0 {
//not prime numbers
prime = false
}
}
if prime == true {
print(n)
}
}
}
}
You can do it like this. Just exclude 1 and n.
Is it possible to break from a Groovy .each{Closure}, or should I be using a classic loop instead?
Nope, you can't abort an "each" without throwing an exception. You likely want a classic loop if you want the break to abort under a particular condition.
Alternatively, you could use a "find" closure instead of an each and return true when you would have done a break.
This example will abort before processing the whole list:
def a = [1, 2, 3, 4, 5, 6, 7]
a.find {
if (it > 5) return true // break
println it // do the stuff that you wanted to before break
return false // keep looping
}
Prints
1
2
3
4
5
but doesn't print 6 or 7.
It's also really easy to write your own iterator methods with custom break behavior that accept closures:
List.metaClass.eachUntilGreaterThanFive = { closure ->
for ( value in delegate ) {
if ( value > 5 ) break
closure(value)
}
}
def a = [1, 2, 3, 4, 5, 6, 7]
a.eachUntilGreaterThanFive {
println it
}
Also prints:
1
2
3
4
5
Replace each loop with any closure.
def list = [1, 2, 3, 4, 5]
list.any { element ->
if (element == 2)
return // continue
println element
if (element == 3)
return true // break
}
Output
1
3
No, you can't break from a closure in Groovy without throwing an exception. Also, you shouldn't use exceptions for control flow.
If you find yourself wanting to break out of a closure you should probably first think about why you want to do this and not how to do it. The first thing to consider could be the substitution of the closure in question with one of Groovy's (conceptual) higher order functions. The following example:
for ( i in 1..10) { if (i < 5) println i; else return}
becomes
(1..10).each{if (it < 5) println it}
becomes
(1..10).findAll{it < 5}.each{println it}
which also helps clarity. It states the intent of your code much better.
The potential drawback in the shown examples is that iteration only stops early in the first example. If you have performance considerations you might want to stop it right then and there.
However, for most use cases that involve iterations you can usually resort to one of Groovy's find, grep, collect, inject, etc. methods. They usually take some "configuration" and then "know" how to do the iteration for you, so that you can actually avoid imperative looping wherever possible.
Just using special Closure
// declare and implement:
def eachWithBreak = { list, Closure c ->
boolean bBreak = false
list.each() { it ->
if (bBreak) return
bBreak = c(it)
}
}
def list = [1,2,3,4,5,6]
eachWithBreak list, { it ->
if (it > 3) return true // break 'eachWithBreak'
println it
return false // next it
}
You can't break from a Groovy each loop, but you can break from a java "enhanced" for loop.
def a = [1, 2, 3, 4, 5, 6, 7]
for (def i : a) {
if (i < 2)
continue
if (i > 5)
break
println i
}
Output:
2
3
4
5
This might not fit for absolutely every situation but it's helped for me :)
I agree with other answers not to use an exception to break an each. I also do not prefer to create an extra closure eachWithBreak, instead of this I prefer a modern approach: let's use the each to iterate over the collection, as requested, but refine the collection to contain only those elements to be iterated, for example with findAll:
collection.findAll { !endCondition }.each { doSomething() }
For example, if we what to break when the counter == 3 we can write this code (already suggested):
(0..5)
.findAll { it < 3 }
.each { println it }
This will output
0
1
2
So far so good, but you will notice a small discrepancy though. Our end condition, negation of counter == 3 is not quite correct because !(counter==3) is not equivalent with it < 3. This is necessary to make the code work since findAll does not actually break the loop but continues until the end.
To emulate a real situation, let's say we have this code:
for (n in 0..5) {
if (n == 3)
break
println n
}
but we want to use each, so let's rewrite it using a function to simulate a break condition:
def breakWhen(nr) { nr == 3 }
(0..5)
.findAll { !breakWhen(it) }
.each { println it }
with the output:
0
1
2
4
5
now you see the problem with findAll. This does not stop, but ignores that element where the condition is not met.
To solve this issues, we need an extra variable to remember when the breaking condition become true. After this moment, findAll must ignore all remaining elements.
This is how it should look like:
def breakWhen(nr) { nr == 3 }
def loop = true
(0..5)
.findAll {
if (breakWhen(it))
loop = false
!breakWhen(it) && loop
} .each {
println it
}
with the output:
0
1
2
That's what we want!
(1..10).each{
if (it < 5)
println it
else
return false
You could break by RETURN. For example
def a = [1, 2, 3, 4, 5, 6, 7]
def ret = 0
a.each {def n ->
if (n > 5) {
ret = n
return ret
}
}
It works for me!
The program works fine with var dig = 0 and it doesn't work with var dig:Int I get an error: Variable "dig" used before being initialized Could you explain me why?
func myFunc(a:Int, b:Int) {
var c = a / b
var o = a % b
var v = 0
var dig = 0
if o != 0 {println("\(a)/\(b) = \(c) и \(o)/\(b)")}
else {println("\(a)/\(b) = \(c)")}
if a > b {
v = b
}
else {
v = a
}
for var i = 1; i <= v; ++i {
if a % i == 0 && b % i == 0 {dig = i}
}
println("\(dig) - greatest common denominator of \(a) and \(b)")
}
myFunc(27,81)
The only place you set the value of dig is inside of an if statement that is inside of a for loop. The Swift compiler does not know if the body of the for loop will be executed, and it doesn't know if the if statement will ever be true, so it has to assume that there is a path in which dig is not initialized.
Consider this simpler example:
func myFunc(a:Int, b:Int) {
var dig: Int
if a >= b {
dig = 3
}
if a < b {
dig = 4
}
println("\(dig) - greatest common denominator of \(a) and \(b)")
}
This example also gives the same error, because Swift considers each if separately. It is obvious to us that a is either greater than or equal to b or it is less than b, but Swift doesn't go that far in evaluating the situation. It just considers that each if may not be true, and dig is only set inside of ifs, so it is possible (as far as Swift is concerned) that dig may not be set.
func myFunc(a:Int, b:Int) {
var dig: Int
if a >= b {
dig = 3
} else {
dig = 4
}
println("\(dig) - greatest common denominator of \(a) and \(b)")
}
If you change the second condition to an else, Swift is then happy because it can reason that the if must be true or false and dig is set in each path, so it will certainly have a value before the println statement.
The compiler does not know mathematics good enough to
recognize that the statement
if a % i == 0 && b % i == 0 {dig = i}
is actually executed at least once (for i == 1). Therefore
the compiler assumes that dig might be undefined at
println("\(dig) - greatest common denominator of \(a) and \(b)")
Assigning an initial value in
var dig = 0
is the correct solution.
Btw., the Euclidean Algorithm is a much more effective method to
compute the greatest common divisor, see for example
http://rosettacode.org/wiki/Greatest_common_divisor#Swift.
Question:
I'm trying to unpack an array into an array, but it only works if it's the last item unpacked, if there is anything after it only the first element is unpacked. The following is a very basic example of what I'm trying to do. Is there a better way to do this, or is this a bug I'll have to cope with? I don't want to use table.insert as this seems to be much more readable adding within the definition of the table with something like unpack.
Code:
print ("Error 1")
local table1 = { {1,1}, {2,2}, {3,3} }
local table2 = { {0,0}, unpack (table1), {4,4} }
for n,item in ipairs (table2) do print (unpack(item)) end
print ("Good")
table1 = { {1,1}, {2,2}, {3,3} }
table2 = { {0,0}, unpack (table1) }
for n,item in ipairs (table2) do print (unpack(item)) end
print ("Error 2")
table1 = { {1,1}, {2,2}, {3,3} }
table2 = { {0,0}, unpack (table1), unpack (table1) }
for n,item in ipairs (table2) do print (unpack(item)) end
Output:
Error 1
0 0
1 1 -- {2,2} & {3,3} cut off.
4 4
Good
0 0
1 1 -- All elements unpacked.
2 2
3 3
Error 2
0 0
1 1 -- {2,2} & {3,3} cut off.
1 1 -- All elements unpacked.
2 2
3 3
Note:
I'm running version 5.1.
This is not a bug. A function call that returns multiple values is adjusted to the first value if the call is not the last one. The manual says that at http://www.lua.org/manual/5.1/manual.html#2.5