Loops/Nested: Difference between revisions
m →{{header|REXX}}: added a comment. -- ~~~~ |
Added BBC BASIC |
||
Line 134:
NEXT col
NEXT row</lang>
=={{header|BBC BASIC}}==
{{works with|BBC BASIC for Windows}}
<lang bbcbasic> DIM array(10,10)
FOR row% = 0 TO 10
FOR col% = 0 TO 10
array(row%,col%) = RND(20) + 1
NEXT
NEXT row%
FOR row% = 0 TO 10
FOR col% = 0 TO 10
IF array(row%,col%) = 20 EXIT FOR row%
NEXT
NEXT row%
IF row%<=10 PRINT "Found at row "; row% " column " ; col%</lang>
EXIT FOR can jump out of multiple nested loops by specifying a control variable.
=={{header|bc}}==
|
Revision as of 14:01, 10 October 2012
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
You are encouraged to solve this task according to the task description, using any language you may know.
Show a nested loop which searches a two-dimensional array filled with random numbers uniformly distributed over . The loops iterate rows and columns of the array printing the elements until the value is met. Specifically, this task also shows how to break out of nested loops.
Ada
<lang ada>with Ada.Text_IO; use Ada.Text_IO; with Ada.Numerics.Discrete_Random;
procedure Test_Loop_Nested is
type Value_Type is range 1..20; package Random_Values is new Ada.Numerics.Discrete_Random (Value_Type); use Random_Values; Dice : Generator; A : array (1..10, 1..10) of Value_Type := (others => (others => Random (Dice)));
begin
Outer :
for I in A'Range (1) loop for J in A'Range (2) loop Put (Value_Type'Image (A (I, J))); exit Outer when A (I, J) = 20; end loop; New_Line; end loop Outer;
end Test_Loop_Nested;</lang>
- Sample output:
16 3 1 17 13 5 4 2 19 1 5 5 17 15 17 2 5 5 17 13 16 10 10 20
ALGOL 68
- note: This specimen retains the original C coding style.
<lang algol68>main: (
[10][10]INT a; INT i, j;
FOR i FROM LWB a TO UPB a DO FOR j FROM LWB a[i] TO UPB a[i] DO a[i][j] := ENTIER (random * 20 + 1) OD OD ; FOR i FROM LWB a TO UPB a DO FOR j FROM LWB a[i] TO UPB a[i] DO print(whole(a[i][j], -3)); IF a[i][j] = 20 THEN GO TO xkcd com 292 # http://xkcd.com/292/ # FI OD; print(new line) OD;
xkcd com 292:
print(new line)
)</lang>
- Sample output:
8 14 17 6 18 1 1 7 9 6 8 9 1 15 3 1 10 19 6 7 12 20
AutoHotkey
<lang AutoHotkey>Loop, 10 {
i := A_Index Loop, 10 { j := A_Index Random, a%i%%j%, 1, 20 }
}
Loop, 10 {
i := A_Index Loop, 10 { j := A_Index If (a%i%%j% == 20) Goto finish }
}
finish:
MsgBox % "a[" . i . "][" . j . "]" is 20
Return</lang>
AWK
To break from two loops, this program uses two break statements and one b flag. <lang awk>BEGIN { rows = 5 columns = 5
# Fill ary[] with random numbers from 1 to 20. for (r = 1; r <= rows; r++) { for (c = 1; c <= columns; c++) ary[r, c] = int(rand() * 20) + 1 }
# Find a 20. b = 0 for (r = 1; r <= rows; r++) { for (c = 1; c <= columns; c++) { v = ary[r, c] printf " %2d", v if (v == 20) { print b = 1 break } } if (b) break print } }</lang>
BASIC
<lang qbasic>DIM a(1 TO 10, 1 TO 10) AS INTEGER CLS FOR row = 1 TO 10
FOR col = 1 TO 10 a(row, col) = INT(RND * 20) + 1 NEXT col
NEXT row
FOR row = LBOUND(a, 1) TO UBOUND(a, 1)
FOR col = LBOUND(a, 2) TO UBOUND(a, 2) PRINT a(row, col) IF a(row, col) = 20 THEN END NEXT col
NEXT row</lang>
BBC BASIC
<lang bbcbasic> DIM array(10,10)
FOR row% = 0 TO 10 FOR col% = 0 TO 10 array(row%,col%) = RND(20) + 1 NEXT NEXT row% FOR row% = 0 TO 10 FOR col% = 0 TO 10 IF array(row%,col%) = 20 EXIT FOR row% NEXT NEXT row% IF row%<=10 PRINT "Found at row "; row% " column " ; col%</lang>
EXIT FOR can jump out of multiple nested loops by specifying a control variable.
bc
Arrays have only one dimension, so we use a[i * c + j] instead of a[i, j].
<lang bc>s = 1 /* Seed of the random number generator */
/* Random number from 1 to 20. */ define r() { auto r while (1) { /* * Formula (from POSIX) for random numbers of low * quality, from 0 to 32767. */ s = (s * 1103515245 + 12345) % 4294967296 r = (s / 65536) % 32768
/* Prevent modulo bias. */ if (r >= 32768 % 20) break } return ((r % 20) + 1) }
r = 5 /* Total rows */ c = 5 /* Total columns */
/* Fill array a[] with random numbers from 1 to 20. */ for (i = 0; i < r; i++) { for (j = 0; j < c; j++) { a[i * c + j] = r() } }
/* Find a 20. */ b = 0 for (i = 0; i < r; i++) { for (j = 0; j < c; j++) { v = a[i * c + j] v /* Print v and a newline. */ if (v == 20) { b = 1 break } } if (b) break /* Print "==" and a newline. */ "== " } quit</lang>
C
Using goto (note: gotos are considered harmful): <lang c>#include <stdlib.h>
- include <time.h>
- include <stdio.h>
int main() {
int a[10][10], i, j;
srand(time(NULL)); for (i = 0; i < 10; i++) for (j = 0; j < 10; j++) a[i][j] = rand() % 20 + 1;
for (i = 0; i < 10; i++) { for (j = 0; j < 10; j++) { printf(" %d", a[i][j]); if (a[i][j] == 20) goto Done; } printf("\n"); }
Done:
printf("\n"); return 0;
}</lang>
C#
Uses goto as C# has no way to break from multiple loops <lang csharp>using System;
class Program {
static void Main(string[] args) { int[,] a = new int[10, 10]; Random r = new Random();
for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { a[i, j] = r.Next(0, 20) + 1; } } for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { Console.Write(" {0}", a[i, j]); if (a[i, j] == 20) { goto Done; } } Console.WriteLine(); } Done: Console.WriteLine(); }
}</lang>
C++
<lang cpp>#include<cstdlib>
- include<ctime>
- include<iostream>
using namespace std; int main() {
int arr[10][10]; srand(time(NULL)); for(auto& row: arr) for(auto& col: row) col = rand() % 20 + 1;
([&](){ for(auto& row : arr) for(auto& col: row) { cout << col << endl; if(col == 20)return; } })(); return 0;
}</lang>
Clojure
We explicitly return a status flag from the inner loop: <lang clojure>(ns nested)
(defn create-matrix [width height]
(for [_ (range width)] (for [_ (range height)] (inc (rand-int 20)))))
(defn print-matrix [matrix]
(loop [[row & rs] matrix] (when (= (loop [[x & xs] row] (println x) (cond (= x 20) :stop xs (recur xs) :else :continue)) :continue) (when rs (recur rs)))))
(print-matrix (create-matrix 10 10))</lang>
Common Lisp
<lang lisp>(let ((a (make-array '(10 10))))
(dotimes (i 10) (dotimes (j 10) (setf (aref a i j) (1+ (random 20))))) (block outer (dotimes (i 10) (dotimes (j 10) (princ " ") (princ (aref a i j)) (if (= 20 (aref a i j)) (return-from outer))) (terpri)) (terpri)))</lang>
D
<lang d>import std.stdio, std.random;
void main() {
int[10][10] mat; foreach (ref row; mat) foreach (ref item; row) item = uniform(1, 21);
outer: foreach (row; mat) foreach (item; row) { write(item, ' '); if (item == 20) break outer; }
writeln();
}</lang>
Delphi /Pascal
<lang delphi>var
matrix: array[1..10,1..10] of Integer; row, col: Integer; broken: Boolean;
begin
// Launch random number generator randomize; // Filling matrix with random numbers for row := 1 to 10 do for col := 1 to 10 do matrix[row, col] := Succ(Random(20)); // Displaying values one by one, until at the end or reached number 20 Broken := False; for row := 1 to 10 do begin for col := 1 to 10 do begin ShowMessage(IntToStr(matrix[row, col])); if matrix[row, col] = 20 then begin Broken := True; break; end; end; if Broken then break; end;
end;</lang>
dc
A single Q command can break multiple nested loops.
<lang dc>1 ss [Seed of the random number generator.]sz
[*
* lrx -- (number) * Push a random number from 1 to 20. *]sz
[
[ [If preventing modulo bias:]sz sz [Drop this random number.]sz lLx [Loop.]sz ]SI [ [Loop:]sz [* * Formula (from POSIX) for random numbers of low quality. * Push a random number from 0 to 32767. *]sz ls 1103515245 * 12345 + 4294967296 % ss ls 65536 / 32768 %
d 32768 20 % >I [Prevent modulo bias.]sz ]d SL x 20 % 1 + [Be from 1 to 20.]sz LLsz LIsz [Restore L, I.]sz
]sr
5 sb [b = Total rows]sz
5 sc [c = Total columns]sz
[Fill array a[] with random numbers from 1 to 20.]sz [ [Inner loop for j:]sz
lrx [Push random number.]sz li lc * lj + [Push index of a[i, j].]sz :a [Put in a[].]sz lj 1 + d sj [j += 1]sz lc >I [Loop while c > j.]sz
]sI [ [Outer loop for i:]sz
0 d sj [j = 0]sz lc >I [Enter inner loop.]sz li 1 + d si [i += 1]sz lb >L [Loop while b > i.]sz
]sL 0 d si [i = 0]sz lb >L [Enter outer loop.]sz
[Find a 20.]sz [ [If detecting a 20:]sz
li lj + 3 + Q [Break outer loop.]sz
]sD [ [Inner loop for j:]sz
li lc * lj + [Push index of a[i,j].]sz ;a [Push value from a[].]sz p [Print value and a newline.]sz 20 =D [Detect a 20.]sz lj 1 + d sj [j += 1]sz lc >I [Loop while c > j.]sz
]sI [ [Outer loop for i:]sz
0 d sj [j = 0]sz lc >I [Enter inner loop.]sz [==
]P [Print "==" and a newline.]sz
li 1 + d si [i += 1]sz lb >L [Loop while b > i.]sz
]sL 0 d si [i = 0]sz lb >L [Enter outer loop.]sz</lang> In this program, li lj + 3 + Q breaks both the inner loop and the outer loop. We must count how many levels of string execution to break. Our loops use tail recursion, so each iteration is a level of string execution. We have i + 1 calls to outer loop L, and j + 1 calls to inner loop I, and 1 call to condition D; so we break i + j + 3 levels with li lj + 3 + Q.
E
<lang e>def array := accum [] for i in 1..5 { _.with(accum [] for i in 1..5 { _.with(entropy.nextInt(20) + 1) }) }
escape done {
for row in array { for x in row { print(`$x$\t`) if (x == 20) { done() } } println() }
} println("done.")</lang>
Euphoria
<lang euphoria>sequence a a = rand(repeat(repeat(20, 10), 10))
integer wantExit wantExit = 0
for i = 1 to 10 do
for j = 1 to 10 do
printf(1, "%g ", {a[i][j]}) if a[i][j] = 20 then wantExit = 1 exit end if
end for if wantExit then
exit
end if
end for</lang>
exit
only breaks out of the innermost loop. A better way to do this would be a procedure.
Fantom
There is no specific way to break out of nested loops (such as a labelled break, or goto). Instead, we can use exceptions and a try-catch block. <lang fantom>class Main {
public static Void main () { rows := 10 cols := 10 // create and fill an array of given size with random numbers Int[][] array := [,] rows.times { row := [,] cols.times { row.add(Int.random(1..20)) } array.add (row) } // now do the search try { for (i := 0; i < rows; i++) { for (j := 0; j < cols; j++) { echo ("now at ($i, $j) which is ${array[i][j]}") if (array[i][j] == 20) throw (Err("found it")) } } } catch (Err e) { echo (e.msg) return // and finish } echo ("No 20") }
}</lang>
Forth
<lang forth>include random.fs
10 constant X 10 constant Y
- ,randoms ( range n -- ) 0 do dup random 1+ , loop drop ;
create 2darray 20 X Y * ,randoms
- main
Y 0 do cr X 0 do j X * i + cells 2darray + @ dup . 20 = if unloop unloop exit then loop loop ;</lang>
Fortran
<lang fortran> PROGRAM LOOPNESTED
INTEGER A, I, J, RNDINT
C Build a two-dimensional twenty-by-twenty array.
DIMENSION A(20,20)
C It doesn't matter what number you put here.
CALL SDRAND(123)
C Fill the array with random numbers.
DO 20 I = 1, 20 DO 10 J = 1, 20 A(I, J) = RNDINT(1, 20) 10 CONTINUE 20 CONTINUE
C Print the numbers.
DO 40 I = 1, 20 DO 30 J = 1, 20 WRITE (*,5000) I, J, A(I, J)
C If this number is twenty, break out of both loops.
IF (A(I, J) .EQ. 20) GOTO 50 30 CONTINUE 40 CONTINUE
C If we had gone to 40, the DO loop would have continued. You can C label STOP instead of adding another CONTINUE, but it is good C form to only label CONTINUE statements as much as possible.
50 CONTINUE STOP
C Print the value so that it looks like one of those C arrays that C makes everybody so comfortable.
5000 FORMAT('A[', I2, '][', I2, '] is ', I2) END
C FORTRAN 77 does not have come with a random number generator, but it C is easy enough to type "fortran 77 random number generator" into your C preferred search engine and to copy and paste what you find. The C following code is a slightly-modified version of: C C http://www.tat.physik.uni-tuebingen.de/ C ~kley/lehre/ftn77/tutorial/subprograms.html
SUBROUTINE SDRAND (IRSEED) COMMON /SEED/ UTSEED, IRFRST UTSEED = IRSEED IRFRST = 0 RETURN END INTEGER FUNCTION RNDINT (IFROM, ITO) INTEGER IFROM, ITO PARAMETER (MPLIER=16807, MODLUS=2147483647, & & MOBYMP=127773, MOMDMP=2836) COMMON /SEED/ UTSEED, IRFRST INTEGER HVLUE, LVLUE, TESTV, NEXTN SAVE NEXTN IF (IRFRST .EQ. 0) THEN NEXTN = UTSEED IRFRST = 1 ENDIF HVLUE = NEXTN / MOBYMP LVLUE = MOD(NEXTN, MOBYMP) TESTV = MPLIER*LVLUE - MOMDMP*HVLUE IF (TESTV .GT. 0) THEN NEXTN = TESTV ELSE NEXTN = TESTV + MODLUS ENDIF IF (NEXTN .GE. 0) THEN RNDINT = MOD(MOD(NEXTN, MODLUS), ITO - IFROM + 1) + IFROM ELSE RNDINT = MOD(MOD(NEXTN, MODLUS), ITO - IFROM + 1) + ITO + 1 ENDIF RETURN END</lang>
- Sample output:
A[ 1][ 1] is 2 A[ 1][ 2] is 16 A[ 1][ 3] is 16 A[ 1][ 4] is 3 A[ 1][ 5] is 16 A[ 1][ 6] is 15 A[ 1][ 7] is 18 A[ 1][ 8] is 14 A[ 1][ 9] is 9 A[ 1][10] is 10 A[ 1][11] is 12 A[ 1][12] is 15 A[ 1][13] is 3 A[ 1][14] is 19 A[ 1][15] is 20
<lang fortran>program Example
implicit none
real :: ra(5,10) integer :: ia(5,10) integer :: i, j
call random_number(ra) ia = int(ra * 20.0) + 1
outer: do i = 1, size(ia, 1)
do j = 1, size(ia, 2) write(*, "(i3)", advance="no") ia(i,j) if (ia(i,j) == 20) exit outer end do write(*,*) end do outer
end program Example</lang>
- Sample output:
14 2 1 11 8 1 14 11 3 15 7 15 16 6 7 17 3 20
Go
<lang go>package main
import (
"fmt" "math/rand" "time"
)
func main() {
rand.Seed(time.Now().UnixNano())
values := make([][]int, 10) for i := range values { values[i] = make([]int, 10) for j := range values[i] { values[i][j] = rand.Intn(20) + 1 } }
outerLoop:
for i, row := range values { fmt.Printf("%3d)", i) for _, value := range row { fmt.Printf(" %3d", value) if value == 20 { break outerLoop } } fmt.Printf("\n") } fmt.Printf("\n")
}</lang>
Groovy
Solution: <lang groovy>final random = new Random() def a = [] (0..<10).each {
def row = [] (0..<10).each { row << (random.nextInt(20) + 1) } a << row
}
a.each { println it } println ()
Outer: for (i in (0..<a.size())) {
for (j in (0..<a[i].size())) { if (a[i][j] == 20){ println ([i:i, j:j]) break Outer } }
}</lang>
- Output:
[1, 19, 14, 16, 3, 12, 14, 18, 12, 6] [6, 3, 8, 9, 17, 4, 10, 15, 17, 17] [5, 12, 13, 1, 8, 18, 8, 15, 3, 20] [8, 9, 6, 7, 2, 20, 17, 13, 6, 16] [18, 6, 11, 13, 16, 20, 7, 3, 1, 14] [6, 6, 19, 9, 9, 7, 16, 16, 3, 20] [7, 6, 12, 7, 16, 14, 13, 18, 15, 15] [19, 14, 14, 6, 4, 19, 5, 10, 13, 12] [7, 6, 6, 12, 3, 9, 17, 12, 20, 7] [10, 7, 15, 4, 17, 13, 14, 16, 8, 8] [i:2, j:9]
Haskell
<lang haskell>import Data.List
breakIncl p = uncurry ((. take 1). (++)). break p
taskLLB k = map (breakIncl (==k)). breakIncl (k`elem`)</lang>
- Example:
<lang haskell>mij :: Int mij = takeWhile(not.null). unfoldr (Just. splitAt 5) $
[2, 6, 17, 5, 14, 1, 9, 11, 18, 10, 13, 20, 8, 7, 4, 16, 15, 19, 3, 12]
- Main> mapM_ (mapM_ print) $ taskLLB 20 mij
2 6 17 5 14 1 9 11 18 10 13 20</lang>
HicEst
<lang hicest>REAL :: n=20, array(n,n)
array = NINT( RAN(10,10) )
DO row = 1, n
DO col = 1, n WRITE(Name) row, col, array(row,col) IF( array(row, col) == 20 ) GOTO 99 ENDDO
ENDDO
99 END</lang>
Icon and Unicon
Icon and Unicon use 'break' to exit loops and execute an expression argument. To exit nested loops 'break' is repeated as the expression. <lang Icon>procedure main()
every !(!(L := list(10)) := list(10)) := ?20 # setup a 2d array of random numbers up to 20
every i := 1 to *L do # using nested loops
every j := 1 to *L[i] do if L[i,j] = 20 then break break write("L[",i,",",j,"]=20")
end</lang> <lang Icon>every x := L[i := 1 to *L,1 to *L[i]] do
if x = 20 then break write("L[",i,",",j,"]=20") # more succinctly
every if !!L = 20 then break write("Found !!L=20") # even more so (but looses the values of i and j</lang>
J
In J, using loops is usually a bad idea.
Here's how the problem statement (ignoring the "requirement" for loops) could be solved, without loops: <lang J>use=: ({.~ # <. 1+i.&20)@:,</lang> Here's how the problem could be solved, using loops: <lang J>doubleLoop=:verb define
for_row.i.#y do. for_col.i.1{$y do. smoutput t=.(<row,col) { y if.20=t do.return.end. end. end.
)</lang>
- Example use:
use ?.20 20 $ 21 6 17 13 3 5 16 10 4 20 doubleLoop ?.20 20 $ 21 6 17 13 3 5 16 10 4 20
The first approach is probably a couple thousand times faster than the second.
(In real life, good problem definitions might typically involve "use cases" (which are specified in terms of the problem domain, instead in terms of irrelevant details). Of course "Rosetta Code" is about how concepts would be expressed in different languages. However, even here, tasks which dwell on language-specific issues are probably not a good use of people's time.)
Java
<lang java>import java.util.Random;
public class NestedLoopTest {
public static final Random gen = new Random(); public static void main(String[] args) { int[][] a = new int[10][10]; for (int i = 0; i < a.length; i++) for (int j = 0; j < a[i].length; j++) a[i][j] = gen.nextInt(20) + 1;
Outer:for (int i = 0; i < a.length; i++) { for (int j = 0; j < a[i].length; j++) { System.out.print(" " + a[i][j]); if (a[i][j] == 20) break Outer; //adding a label breaks out of all loops up to and including the labelled loop } System.out.println(); } System.out.println(); }
}</lang>
JavaScript
Demonstrates use of break
with a label.
Uses print()
function from Rhino.
<lang javascript>// a "random" 2-D array
var a = [[2, 12, 10, 4], [18, 11, 9, 3], [14, 15, 7, 17], [6, 19, 8, 13], [1, 20, 16, 5]];
outer_loop: for (var i in a) {
print("row " + i); for (var j in a[i]) { print(" " + a[i][j]); if (a[i][j] == 20) break outer_loop; }
} print("done");</lang>
Liberty BASIC
<lang lb>dim ar(10,10) for i = 1 to 10
for j = 1 to 10 ar(i, j) = int(rnd(1) * 20) + 1 next
next
flag=0 for x = 1 to 10
for y = 1 to 10 print ar(x,y) if ar(x,y) = 20 then flag=1 exit for end if next if flag then exit for
next print "Completed row ";x;" and column ";y</lang>
Lisaac
<lang Lisaac>Section Header
+ name := TEST_LOOP_NESTED;
- external := `#include <time.h>`;
Section Public
- main <- (
+ a : ARRAY2[INTEGER]; + i, j: INTEGER;
`srand(time(NULL))`; a := ARRAY2[INTEGER].create(0, 0) to (9, 9); 0.to 9 do { ii : INTEGER; 0.to 9 do { jj : INTEGER; a.put (`rand()`:INTEGER % 20 + 1) to (ii, jj); }; }; { i < 10 }.while_do { j := 0; { j < 10 }.while_do { ' '.print; a.item(i, j).print; (a.item(i, j) = 20).if { i := 999; j := 999; }; j := j + 1; }; i := i + 1; '\n'.print; }; '\n'.print;
);</lang>
Logo
<lang logo>make "a mdarray [10 10]
for [j 1 10] [for [i 1 10] [mdsetitem list :i :j :a (1 + random 20)]]
to until.20
for [j 1 10] [ for [i 1 10] [ type mditem list :i :j :a type "| | if equal? 20 mditem list :i :j :a [stop] ] print "|| ]
end until.20</lang>
Lua
<lang lua>t = {} for i = 1, 20 do
t[i] = {} for j = 1, 20 do t[i][j] = math.random(20) end
end function exitable()
for i = 1, 20 do for j = 1, 20 do if t[i][j] == 20 then return i, j end end end
end print(exitable())</lang>
Mathematica
<lang Mathematica>Do[ Print[mi, j];
If[mi, j === 20, Return[]], {i, 1, Dimensions[m]1}, {j, 1, Dimensions[m]2}]</lang>
MATLAB / Octave
Loops are considered slow in Matlab and Octave, it is preferable to vectorize the code. <lang Matlab> a = ceil(rand(100,100)*20); [ix,iy]=find(a==20,1)</lang> A non-vectorized version of the code is shown below in Octave
Maxima
<lang maxima>data: apply(matrix, makelist(makelist(random(100), 20), 20))$
find_value(a, x) := block(
[p, q], [p, q]: matrix_size(a), catch( for i thru p do for j thru q do if a[i, j] = x then throw([i, j]), 'not\ found )
)$
find_value(data, 100); not found</lang>
MOO
<lang moo>a = make(10, make(10)); for i in [1..10]
for j in [1..10] a[i][j] = random(20); endfor
endfor for i in [1..10]
s = ""; for j in [1..10] s += tostr(" ", a[i][j]); if (a[i][j] == 20) break i; endif endfor player:tell(s); s = "";
endfor player:tell(s);</lang>
MUMPS
<lang MUMPS>NESTLOOP
;.../loops/nested ;set up the 2D array with random values NEW A,I,J,K,FLAG,TRIGGER SET K=15 ;Magic - just to give us a size to work with SET TRIGGER=20 ;Magic - the max value, and the end value FOR I=1:1:K FOR J=1:1:K SET A(I,J)=$RANDOM(TRIGGER)+1 ;Now, search through the array, halting when the value of TRIGGER is found SET FLAG=0 SET (I,J)=0 FOR I=1:1:K Q:FLAG W ! FOR J=1:1:K WRITE A(I,J),$SELECT(J'=K:", ",1:"") SET FLAG=(A(I,J)=TRIGGER) Q:FLAG KILL A,I,J,K,FLAG,TRIGGER QUIT</lang>
- Output:
USER>D NESTLOOP^ROSETTA 16, 4, 6, 20, USER>D NESTLOOP^ROSETTA 9, 10, 10, 13, 2, 9, 6, 10, 1, 12, 12, 10, 8, 1, 13 7, 14, 12, 9, 14, 3, 20,
Nemerle
Nemerle can jump out of a named block by invoking the blocks name with an optional return value. <lang Nemerle>using System; using System.Console; using Nemerle.Imperative;
module NestedLoops {
Main() : void { def arr = array(10, 10); def rnd = Random(); foreach ((i, j) in $[(i, j) | i in [0 .. 9], j in [0 .. 9]]) arr[i, j] = rnd.Next(1, 21); Finish: { foreach ((i, j) in $[(i, j) | i in [0 .. 9], j in [0 .. 9]]) { Write("{0} ", arr[i, j]); when (arr[i, j] == 20) Finish(); } } }
}</lang>
NetRexx
<lang NetRexx>/* NetRexx */ options replace format comments java crossref savelog symbols nobinary
say say 'Loops/Nested'
rnd = Random() dim2 = int[10, 10]
-- build sample data loop i1 = 0 for dim2.length loop i2 = 0 for dim2[i1].length dim2[i1, i2] = rnd.nextInt(20) + 1 end i2 end i1
-- run test loop x1 = 0 for dim2.length say Rexx(x1 + 1).right(4)': \-' loop x2 = 0 for dim2[x1].length say Rexx(dim2[x1, x2]).right(3) || '\-' if dim2[x1, x2] = 20 then leave x1 finally say end x2 finally say end x1</lang>
I was somewhat disappointed by the performance of the above program and started a little performance analysis on solutions of this task for the languages I know.
I created a test program with a 500 + 500 matrix, all elements set to 0 except for the last one, which I set to 20. Then I repeat the search 100 times.
The timings are:
Seconds elapsed 3.978 NetRexx as above 0.032 Netrex with option binary 7.223 ooRexx with x[i,j] 6.490 ooRexx with x.i.j 0.188 PL/I Matrix as coded: FIXED 0.058 PL/I Matrix BIN FIXED(15)
OCaml
In the interactive interpreter:
<lang ocaml>$ ocaml
- Random.self_init();;
- : unit = ()
- let m = Array.make_matrix 10 10 0 ;;
val m : int array array =
[|[|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|]; [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|]; [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|]; [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|]; [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|]; [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|]; [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|]; [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|]; [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|]; [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|]|]
- for i = 0 to pred 10 do
for j = 0 to pred 10 do m.(i).(j) <- 1 + Random.int 20 done; done;;
- : unit = ()
- try
for i = 0 to pred 10 do for j = 0 to pred 10 do Printf.printf " %d" m.(i).(j); if m.(i).(j) = 20 then raise Exit; done; print_newline() done; with Exit -> print_newline() ;; 15 8 15 9 9 6 1 18 6 18 17 1 13 15 13 1 16 4 13 9 15 3 5 19 17 3 1 11 5 2 1 1 6 19 20
- : unit = ()</lang>
Octave
Octave has no way of exiting nested loop; so we need a control variable, or we can use the trick of embedding the loops into a function and use the return statement. (The search for "exactly 20" is changed into a search for "almost 20") <lang octave>function search_almost_twenty() % create a 100x100 matrix... m = unifrnd(0,20, 100,100); for i = 1:100
for j = 1:100 disp( m(i,j) ) if ( abs(m(i,j) - 20) < 1e-2 ) return endif endfor
endfor endfunction
search_almost_twenty()
% avoiding function, we need a control variable. m = unifrnd(0,20, 100,100); innerloopbreak = false; for i = 1:100
for j = 1:100 disp( m(i,j) ) if ( abs(m(i,j) - 20) < 1e-2 ) innerloopbreak = true; break; endif endfor if ( innerloopbreak ) break; endif
endfor</lang>
OOREXX
<lang oorexx>numbers = .array~new() do i = 1 to 10
do j = 1 to 10 numbers[i,j] = random(1, 20) end
end
do i = 1 to numbers~dimension(1)
do j = 1 to numbers~dimension(2) say numbers[i,j] if numbers[i,j] = 20 then leave i end
end</lang>
Oz
We can directly access and use the outer loop's break procedure: <lang oz>declare
fun {CreateMatrix Width Height} Matrix = {List.make Height} in for Row in Matrix do Row = {List.make Width} for X in Row do X = {OS.rand} mod 20 +1 end end Matrix end
proc {PrintMatrix Matrix} %% print until we see 20 for Row in Matrix break:OuterBreak do for X in Row do {Show X} if X == 20 then {OuterBreak} end end end end
in
{PrintMatrix {CreateMatrix 10 10}}</lang>
PARI/GP
<lang parigp>M=matrix(10,10,i,j,random(20)+1); for(i=1,10,for(j=1,10,if(M[i,j]==20,break(2))))</lang>
Perl
<lang perl>my $a = [ map [ map { int(rand(20)) + 1 } 1 .. 10 ], 1 .. 10];
Outer: foreach (@$a) {
foreach (@$_) { print " $_"; if ($_ == 20) { last Outer; } } print "\n";
} print "\n";</lang>
Perl 6
<lang perl6>my @a := [ (1..20).roll(10) ] xx *;
LINE: for @a -> @line {
for @line -> $elem { print " $elem"; last LINE if $elem == 20; } print "\n";
} print "\n";</lang> Rakudo does not implement loop labels yet, but at least we can catch the error of trying to use one: <lang perl6>my @a := [ (1..20).roll(10) ] xx *;
try {
# LINE: for @a -> @line { for @line -> $elem { print " $elem"; last LINE if $elem == 20; } print "\n"; }
} print "\n";</lang>
- Output:
15 6 14 13 14 7 9 16 8 18 7 6 18 11 19 13 12 5 18 8 17 17 9 5 4 8 17 8 3 11 9 20
PHP
<lang php><?php for ($i = 0; $i < 10; $i++)
for ($j = 0; $j < 10; $j++) $a[$i][$j] = rand(1, 20);
foreach ($a as $row) {
foreach ($row as $element) { echo " $element"; if ($element == 20) break 2; // 2 is the number of loops we want to break out of } echo "\n";
} echo "\n"; ?></lang>
PicoLisp
<lang PicoLisp>(for Lst (make (do 10 (link (make (do 10 (link (rand 1 20)))))))
(T (for N Lst (printsp N) (T (= N 20) T) ) ) )</lang>
or: <lang PicoLisp>(catch NIL
(for Lst (make (do 10 (link (make (do 10 (link (rand 1 20))))))) (for N Lst (printsp N) (and (= N 20) (throw)) ) ) )</lang>
PL/I
<lang PL/I> declare x(20,20) fixed; /* 16 August 2010. */
x = random()*20 + 1;
loops:
do i = 1 to hbound(x,1); do j = 1 to hbound(x,2); put (x(i,j)); if x(i,j) = 20 then leave loops; end; if x(i,j) = 20 then leave; end;</lang>
PureBasic
<lang PureBasic>; Creating and filling array Dim Value(10, 5) For a = 0 To 10
For b = 0 To 5 Value(a, b) = Random(19) + 1 Next
Next
- iterating trough array
For a = 0 To 10
For b = 0 To 5 Debug Value(a, b) If Value(a, b) = 20 ; 2 indicates, that there are two nested lopps to break out Break 2 EndIf Next
Next</lang>
Python
Python has only inner loop breaks. The normal way to solve this problem in Python is to move the code in a function, and use return: <lang python>from random import randint
def do_scan(mat):
for row in mat: for item in row: print item, if item == 20: print return print print
mat = [[randint(1, 20) for x in xrange(10)] for y in xrange(10)] do_scan(mat)</lang> The , after print element suppresses printing a line break. The code needs some minor changes for Python 3.
Two more solutions around this problem, the first uses exception handling: <lang python>from random import randint
class Found20(Exception):
pass
mat = [[randint(1, 20) for x in xrange(10)] for y in xrange(10)]
try:
for row in mat: for item in row: print item, if item == 20: raise Found20 print
except Found20:
print</lang>
The second uses a flag variable: <lang python>from random import randint
mat = [[randint(1, 20) for x in xrange(10)] for y in xrange(10)]
found20 = False for row in mat:
for item in row: print item, if item == 20: found20 = True break print if found20: break</lang>
Qi
<lang Qi> (define random-list
0 -> [] M -> [(1+ (RANDOM 20)) | (random-list (1- M))])
(define random-array
0 _ -> [] N M -> [(random-list M) | (random-array (1- N) M)])
(define array->list
_ [] -> [] \ "end outer loop" \ Stop [[] | Ra] -> (array->list Stop Ra) \ "outer loop" \ Stop [[Stop | _ ] | _ ] -> [] \ "break out from inner loop" \ Stop [[X | Rl] | Ra] -> [X | (array->list Stop [Rl | Ra])]) \ "inner loop" \
(array->list 20 (random-array 10 10)) </lang>
R
<lang R>m <- 10 n <- 10 mat <- matrix(sample(1:20L, m*n, replace=TRUE), nrow=m); mat done <- FALSE for(i in seq_len(m)) {
for(j in seq_len(n)) { cat(mat[i,j]) if(mat[i,j] == 20) { done <- TRUE break } cat(", ") } if(done) { cat("\n") break }
}</lang>
or
<lang R> m <- 10; n <- 10; mat <- matrix(sample(1:20L, m*n, replace=TRUE), nrow=m); x<-which(mat==20,arr.ind=TRUE,useNames=FALSE) x<-x[order(x[,1]),] for(i in mat[1:x[1,1]-1,]) print(i) for(i in mat[x[1,1],1:x[1,2]]) print(i) </lang>
REBOL
<lang REBOL>REBOL [ Title: "Loop/Nested" Author: oofoe Date: 2010-01-05 URL: http://rosettacode.org/wiki/Loop/Nested ]
- Number formatting.
zeropad: func [pad n][
n: to-string n insert/dup n "0" (pad - length? n) n]
- Initialize random number generator from current time.
random/seed now
- Create array and fill with random numbers, range 1..20.
soup: array [10 10] repeat row soup [forall row [row/1: random 20]]
print "Loop break using state variable:" done: no for y 1 10 1 [ for x 1 10 1 [ prin rejoin [zeropad 2 soup/:x/:y " "] if 20 = soup/:x/:y [done: yes break] ] prin crlf if done [break] ]
print [crlf "Loop break with catch/throw:"] catch [ for y 1 10 1 [ for x 1 10 1 [ prin rejoin [zeropad 2 soup/:x/:y " "] if 20 = soup/:x/:y [throw 'done] ] prin crlf ] ] prin crlf</lang>
- Output:
Loop break using state variable: 15 09 11 03 17 07 09 16 03 07 03 15 04 06 13 05 10 06 02 14 17 05 06 12 03 19 03 03 17 04 17 15 14 17 15 07 06 16 13 11 02 08 12 16 04 14 03 19 02 02 02 13 14 14 15 01 10 07 17 03 07 17 20 Loop break with catch/throw: 15 09 11 03 17 07 09 16 03 07 03 15 04 06 13 05 10 06 02 14 17 05 06 12 03 19 03 03 17 04 17 15 14 17 15 07 06 16 13 11 02 08 12 16 04 14 03 19 02 02 02 13 14 14 15 01 10 07 17 03 07 17 20
REXX
<lang rexx>/*REXX program to loop through a 2-dimensional array to look for a '20'.*/ rows=60 cols=10
do row =1 for rows /*1st dimension ∙∙∙ */ do col=1 for cols /*2nd dimension ∙∙∙ */ @.row.col=random(1,20) /*generate some nums.*/ end /*row*/ end /*col*/
/*─────────────────────────────────────now, search for the hidden twenty*/
do r =1 for rows do c=1 for cols say left('@.'r"."c,9) '=' right(@.r.c,4) if @.r.c==20 then leave r end /*c*/ end /*r*/
say right(' Done with Loops/Nested. ',50,'─')
/*stick a fork in it, we're done.*/</lang>
output
@.1.1 = 15 @.1.2 = 14 @.1.3 = 9 @.1.4 = 5 @.1.5 = 1 @.1.6 = 17 @.1.7 = 4 @.1.8 = 16 @.1.9 = 8 @.1.10 = 16 @.2.1 = 16 @.2.2 = 5 @.2.3 = 19 @.2.4 = 20 ───────────────────────── Done with Loops/Nested.
Ruby
As the break command only jumps out of the innermost loop, this task requires Ruby's catch/throw
functionality.
<lang ruby>srand
ary = (1..20).to_a.shuffle.each_slice(4).to_a
p ary
catch :found_it do
for row in ary for element in row print "%2d " % element throw :found_it if element == 20 end puts "," end
end
puts "done"</lang>
- Output:
[[2, 12, 10, 4], [18, 11, 9, 3], [14, 15, 7, 17], [6, 19, 8, 13], [1, 20, 16, 5]] 2 12 10 4 , 18 11 9 3 , 14 15 7 17 , 6 19 8 13 , 1 20 done
Run BASIC
<lang runbasic>dim a(10,10) cls for row = 1 TO 10
for col = 1 TO 10 a(row,col) = INT(20 * RND(1) + 1) next col
next row
for row = 1 to 10
for col = 1 to 10 print a(row, col) if a(row, col) = 20 then goto [end] next col
next row [end] print "At row:";row;" col:";col</lang>
Sather
<lang sather>class MAIN is
main is a:ARRAY2{INT} := #(10,10); i, j :INT; RND::seed(1230); loop i := 0.upto!(9); loop j := 0.upto!(9); a[i, j] := RND::int(1, 20); end; end;
loopthis ::= true; loop i := 0.upto!(9); while!( loopthis ); loop j := 0.upto!(9); #OUT + " " + a[i, j]; if a[i, j] = 20 then
loopthis := false; break!; end;
end; end; end;
end;</lang>
Scala
In Scala there is no build-in 'break' keyword. That functionality comes from a library. <lang scala>import scala.util.control.Breaks._ val a=Array.fill(5,4)(scala.util.Random.nextInt(21)) println(a map (_.mkString("[", ", ", "]")) mkString "\n") breakable {
for(row <- a; x <- row){ println(x) if (x==20) break }
}</lang> Sample output:
[14, 16, 5, 7] [0, 15, 13, 20] [0, 3, 8, 17] [4, 20, 2, 2] [12, 6, 11, 15] 14 16 5 7 0 15 13 20
Scheme
Using call/cc: <lang scheme>(call-with-current-continuation
(lambda (return) (for-each (lambda (a)
(for-each (lambda (b) (cond ((= 20 b) (newline) (return)) (else (display " ")(display b)))) a) (newline)) array)))</lang> Using tail-call: <lang scheme>(let loop ((a array))
(if (pair? a) (let loop2 ((b (car a)))
(cond ((null? b) (newline) (loop (cdr a))) ((= 20 (car b)) (newline)) (else (display " ")(display (car b)) (loop2 (cdr b)))))))</lang>
Smalltalk
Smalltalk has no ways of escaping from loops (single or nested), even if it is possible to extend its iteration capabilities in several ways. The following code implements a BiArray class with a method that allows iteration over the elements (by columns and then by rows) and execution of a block if a condition is true. <lang smalltalk>"this simple implementation of a bidimensional array
lacks controls over the indexes, but has a way of iterating over array's elements, from left to right and top to bottom"
Object subclass: BiArray [
|cols rows elements| BiArray class >> columns: columns rows: howManyRows [ ^ super basicNew init: columns per: howManyRows ] init: columns per: howManyRows [ cols := columns. rows := howManyRows. elements := Array new: ( columns * howManyRows ) ] calcIndex: biIndex [ "column, row (x,y) to linear" ^ ( (biIndex at: 1) + (((biIndex at: 2) - 1) * cols) ) ] at: biIndex [ "biIndex is an indexable containing column row" ^ elements at: (self calcIndex: biIndex). ] directAt: i [ ^ elements at: i ] at: biIndex put: anObject [ elements at: (self calcIndex: biIndex) put: anObject ] whileTrue: aBlock do: anotherBlock [ |i lim| i := 1. lim := rows * cols. [ ( i <= lim ) & (aBlock value: (self directAt: i) ) ] whileTrue: [ anotherBlock value: (self directAt: i). i := i + 1. ] ]
].
|biarr| biarr := BiArray columns: 10 rows: 10.
"fill the array; this illustrates nested loop but not how to
escape from them"
1 to: 10 do: [ :c |
1 to: 10 do: [ :r | biarr at: {c . r} put: (Random between: 1 and: 20) ]
].
"loop searching for 20; each block gets the element passed as argument" biarr whileTrue: [ :v | v ~= 20 ]
do: [ :v | v displayNl ]</lang>
Tcl
Tcl only supports single-level breaks; exiting more deeply nested looping requires the use of exceptions, which are considerably more verbose before Tcl 8.6.
<lang tcl>set ary [subst [lrepeat 10 [lrepeat 5 {[expr int(rand()*20+1)]}]]]
try {
foreach row $ary { foreach col $row { puts -nonewline [format %3s $col] if {$col == 20} { throw MULTIBREAK "we're done" } } puts , }
} trap MULTIBREAK {} {} puts " done"</lang> Sample output:
12 13 14 13 15, 1 14 7 16 3, 12 11 5 1 9, 12 5 1 4 2, 6 11 11 4 11, 7 14 20 done
TI-89 BASIC
The Stop
statement exits the containing program.
<lang ti89b>Prgm
Local mat,i,j © randMat(5, 5) exists but returns -9 to 9 rather than 1 to 20 newMat(5, 5) → mat For i,1,rowDim(mat) For j,1,colDim(mat) rand(20) → mat[i,j] EndFor EndFor Disp mat Pause "Press a key." ClrIO For i,1,rowDim(mat) For j,1,colDim(mat) If mat[i,j] = 20 Then Stop Else Output i*8, j*18, mat[i,j] EndIf EndFor EndFor
EndPrgm</lang>
TUSCRIPT
<lang tuscript>$$ MODE TUSCRIPT LOOP row=""
LOOP/CLEAR x=1,10 x=RANDOM_NUMBERS (1,20,1) row=APPEND(row," ",x) IF (x==20) THEN PRINT row EXIT,EXIT ENDIF ENDLOOP PRINT row
ENDLOOP</lang>
- Output:
9 6 6 5 10 18 11 17 17 9 5 16 2 4 2 15 13 13 4 9 12 4 6 19 3 1 3 12 13 8 3 7 4 8 15 12 1 20
UNIX Shell
Bash doesn't have two-dimentional arrays, so we fake it for this example <lang bash>size=10
for ((i=0;i<size;i++)); do
unset t[@] for ((j=0;j<size;j++)); do t[$j]=$((RANDOM%20+1)) done a[$i]="${t[*]}"
done
for ((i=0;i<size;i++)); do
t=(${a[$i]}) for ((j=0;j<size;j++)); do printf "%2d " ${t[$j]} [ ${t[$j]} -eq 20 ] && break 2 done echo
done echo</lang>
- Example output:
7 5 4 6 4 5 2 15 10 7 15 4 14 9 10 14 14 3 3 5 14 20
XPL0
<lang XPL0>include c:\cxpl\codes; \intrinsic 'code' declarations def Size=10;
proc Nest(A); \Display 2-dimensional array A contents until 20 is found int A; int I, J, K; [for J:= 0 to Size-1 do
for I:= 0 to Size-1 do [K:= A(I,J); IntOut(0, K); ChOut(0, ^ ); if K = 20 then return; \there is no 'goto' instruction ];
]; \Nest
proc Fill(A); \Fill 2-dimensional array A with random numbers 1..20 int A; int I, J; [for J:= 0 to Size-1 do
for I:= 0 to Size-1 do A(I,J):= Ran(20)+1;
]; \Fill
int Array(Size,Size); [Fill(Array);
Nest(Array);
]</lang>
ZX Spectrum Basic
<lang zxbasic>10 DIM a(10,10) 20 FOR i=1 TO 10: FOR j=1 TO 10 30 LET a(i,j)=INT (RND*20)+1 40 NEXT j: NEXT i 50 LET b=0: REM flag to abort loops 60 FOR i=1 TO 10: FOR j=1 TO 10 70 PRINT (" " AND a(i,j)<10);a(i,j);" "; 80 IF a(i,j)=20 THEN LET i=10: LET j=10: LET b=1: REM abort loops 90 NEXT j 100 IF b=0 THEN PRINT 110 NEXT i 120 STOP </lang>
- Example output:
16 7 8 6 14 8 12 14 12 9 7 9 14 8 18 17 3 16 1 19 5 13 7 11 13 14 4 7 19 14 20
- Programming Tasks
- Iteration
- Loop modifiers
- Ada
- ALGOL 68
- AutoHotkey
- AWK
- BASIC
- BBC BASIC
- Bc
- C
- C sharp
- C++
- Clojure
- Common Lisp
- D
- Delphi
- Pascal
- Dc
- E
- Euphoria
- Fantom
- Forth
- Fortran
- Go
- Groovy
- Haskell
- HicEst
- Icon
- Unicon
- J
- Java
- JavaScript
- Liberty BASIC
- Lisaac
- Logo
- Lua
- Mathematica
- MATLAB
- Octave
- Maxima
- MOO
- MUMPS
- Nemerle
- NetRexx
- OCaml
- OOREXX
- Oz
- PARI/GP
- Perl
- Perl 6
- PHP
- PicoLisp
- PL/I
- PureBasic
- Python
- Qi
- R
- REBOL
- REXX
- Ruby
- Run BASIC
- Sather
- Scala
- Scheme
- Smalltalk
- Tcl
- TI-89 BASIC
- TUSCRIPT
- UNIX Shell
- XPL0
- ZX Spectrum Basic
- GUISS/Omit