Loops/Nested
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.
- Related tasks
- Loop over multiple arrays simultaneously
- Loops/Break
- Loops/Continue
- Loops/Do-while
- Loops/Downward for
- Loops/For
- Loops/For with a specified step
- Loops/Foreach
- Loops/Increment loop index within loop body
- Loops/Infinite
- Loops/N plus one half
- Loops/Nested
- Loops/While
- Loops/with multiple ranges
- Loops/Wrong ranges
11l
<lang 11l>Int mat L 10
mat [+]= (1..10).map(x -> random:(1..20))
L(row) mat
L(el) row print(el, end' ‘ ’) I el == 20 L(row).break</lang>
360 Assembly
<lang 360asm>* Loop nested 12/08/2015 LOOPNEST CSECT
USING LOOPNEST,R12 LR R12,R15
BEGIN LA R6,0 i
LA R8,1 LA R9,20
LOOPI1 BXH R6,R8,ELOOPI1 do i=1 to hbound(x,1)
LA R7,0 j LA R10,1 LA R11,20
LOOPJ1 BXH R7,R10,ELOOPJ1 do j=1 to hbound(x,2)
L R5,RANDSEED n M R4,=F'397204094' r4r5=n*const D R4,=X'7FFFFFFF' r5=r5 div (2^31-1) ST R4,RANDSEED r4=r5 mod (2^31-1) ; n=r4 LR R5,R4 r5=n LA R4,0 D R4,=F'20' r5=n div nn; r4=n mod nn LR R2,R4 r2=randint(nn) [0:nn-1] LA R2,1(R2) randint(nn)+1 LR R1,R6 i BCTR R1,0 MH R1,=H'20' LR R5,R7 j BCTR R5,0 AR R1,R5 SLA R1,2 ST R2,X(R1) x(i,j)=randint(20)+1 B LOOPJ1
ELOOPJ1 B LOOPI1 ELOOPI1 MVC MVCZ,=CL80' '
LA R6,0 i LA R8,1 LA R9,20
LOOPI2 BXH R6,R8,ELOOPI2 do i=1 to hbound(x,1)
LA R7,0 j LA R10,1 LA R11,20
LOOPJ2 BXH R7,R10,ELOOPJ2 do j=1 to hbound(x,2)
LR R1,R6 BCTR R1,0 MH R1,=H'20' LR R5,R7 BCTR R5,0 AR R1,R5 SLA R1,2 L R5,X(R1) x(i,j) LR R2,R5 LA R3,MVCZ AH R3,MVCI XDECO R2,XDEC MVC 0(4,R3),XDEC+8 LH R3,MVCI LA R3,4(R3) STH R3,MVCI L R5,X(R1) C R5,=F'20' if x(i,j)=20 BE ELOOPI2 then exit B LOOPJ2
ELOOPJ2 XPRNT MVCZ,80
MVC MVCI,=H'0' MVC MVCZ,=CL80' ' B LOOPI2
ELOOPI2 XPRNT MVCZ,80 RETURN XR R15,R15
BR R14
X DS 400F MVCZ DS CL80 MVCI DC H'0' XDEC DS CL16 RANDSEED DC F'16807' running n
YREGS END LOOPNEST</lang>
- Output:
3 4 1 11 13 17 11 9 8 2 15 19 16 18 1 9 7 16 12 3 11 13 13 6 13 19 9 18 11 4 7 8 6 7 2 10 14 4 5 1 16 14 13 6 11 20
Action!
<lang Action!>PROC Main()
DEFINE PTR="CARD" BYTE i,j,found PTR ARRAY a(10) BYTE ARRAY tmp, a0(10),a1(10),a2(10),a3(10),a4(10), a5(10),a6(10),a7(10),a8(10),a9(10)
a(0)=a0 a(1)=a1 a(2)=a2 a(3)=a3 a(4)=a4 a(5)=a5 a(6)=a6 a(7)=a7 a(8)=a8 a(9)=a9
FOR j=0 TO 9 DO tmp=a(j) FOR i=0 TO 9 DO tmp(i)=Rand(20)+1 OD OD
found=0 FOR j=0 TO 9 DO tmp=a(j) FOR i=0 TO 9 DO PrintB(tmp(i)) Put(32) IF tmp(i)=20 THEN found=1 EXIT FI OD IF found THEN EXIT FI PutE() OD
RETURN</lang>
- Output:
Screenshot from Atari 8-bit computer
12 10 16 15 19 7 1 18 3 11 18 3 7 12 18 17 16 12 14 7 14 5 19 8 9 4 6 12 12 2 15 9 9 1 17 17 2 8 8 14 2 14 14 5 5 6 20
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 60
<lang algol60>'BEGIN' 'COMMENT' Loops/Nested - ALGOL60 - 19/06/2018;
'INTEGER' SEED; 'INTEGER' 'PROCEDURE' RANDOM(N); 'VALUE' N; 'INTEGER' N; 'BEGIN' SEED:=(SEED*19157+12347) '/' 21647; RANDOM:=SEED-(SEED '/' N)*N+1 'END' RANDOM; 'INTEGER' 'ARRAY' A(/1:10,1:10/); 'INTEGER' I,J; SEED:=31569; 'FOR' I:=1 'STEP' 1 'UNTIL' 10 'DO' 'FOR' J:=1 'STEP' 1 'UNTIL' 10 'DO' A(/I,J/):=RANDOM(20); SYSACT(1,6,120);SYSACT(1,8,60);SYSACT(1,12,1);'COMMENT' open print; 'FOR' I:=1 'STEP' 1 'UNTIL' 10 'DO' 'FOR' J:=1 'STEP' 1 'UNTIL' 10 'DO' 'BEGIN' OUTINTEGER(1,A(/I,J/)); 'IF' A(/I,J/)=20 'THEN' 'GOTO' LAB;
'END'; LAB: 'END'</lang>
- Output:
+19 +5 +1 +4 +17 +6 +2 +18 +12 +3 +13 +6 +8 +6 +10 +9 +15 +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
AppleScript
AppleScript has exit repeat to break out of a single loop prematurely, but nothing specifically for nested loops. So either exit repeat must be used twice … <lang applescript>on loopDemo(array, stopVal)
set out to {} repeat with i from 1 to (count array) set inRow to item i of array set outRow to {} repeat with j from 1 to (count inRow) set n to item j of inRow set end of outRow to n if (n = stopVal) then exit repeat # <-- end repeat set end of out to outRow if (n = stopVal) then exit repeat # <-- end repeat return out
end loopDemo</lang> … or of course one or both loops can be specified to terminate at the critical juncture anyway … <lang applescript>on loopDemo(array, stopVal)
set out to {} repeat with i from 1 to (count array) set inRow to item i of array set len to (count inRow) set n to beginning of inRow set outRow to {n} set j to 2 repeat until ((j > len) or (n = stopVal)) # <-- set n to item j of inRow set end of outRow to n set j to j + 1 end repeat set end of out to outRow if (n = stopVal) then exit repeat # <-- end repeat return out
end loopDemo</lang> … or, with the process in a dedicated handler, it can be returned from directly at any point: <lang applescript>on loopDemo(array, stopVal)
set out to {} repeat with i from 1 to (count array) set inRow to item i of array set outRow to {} repeat with j from 1 to (count inRow) set n to item j of inRow set end of outRow to n if (n = stopVal) then return out & {outRow} # <-- end repeat set end of out to outRow end repeat return out
end loopDemo</lang>
Demo: <lang applescript>local array, stopVal, row set array to {} set stopVal to 20 repeat 10 times
set row to {} repeat 10 times set end of row to (random number from 1 to stopVal) end repeat set end of array to row
end repeat loopDemo(array, stopVal) -- Any of the handlers above.</lang>
- Output:
<lang applescript>{{15, 8, 9, 8, 9, 9, 10, 16, 3, 6}, {11, 3, 14, 18, 17, 1, 16, 15, 14, 7}, {4, 20}}</lang>
ARM Assembly
<lang ARM Assembly> /* ARM assembly Raspberry PI */ /* program loopnested.s */
/************************************/ /* Constantes */ /************************************/ .equ STDOUT, 1 @ Linux output console .equ EXIT, 1 @ Linux syscall .equ WRITE, 4 @ Linux syscall
.equ NBVALUECOL, 10
.equ NBLIGNES, 10
.equ MAXVALUE, 20
/*********************************/ /* Initialized data */ /*********************************/ .data sMessResult: .ascii " " sMessValeur: .fill 11, 1, ' ' @ size => 11 szCarriageReturn: .asciz "\n"
.align 4
iGraine: .int 314159
/*********************************/ /* UnInitialized data */ /*********************************/ .bss tiValues: .skip 4 * NBVALUECOL * NBLIGNES /*********************************/ /* code section */ /*********************************/ .text .global main main: @ entry of program
ldr r3,iAdrtiValues mov r4,#0 @ loop indice mov r5,#0 mov r7,#4 * NBVALUECOL
1: @ begin loop 1
mov r0,#MAXVALUE + 1 bl genereraleas @ result 0 to MAXVALUE mul r6,r5,r7 add r6,r4,lsl #2 str r0,[r3,r6] add r4,#1 cmp r4,#NBVALUECOL blt 1b mov r4,#0 add r5,#1 cmp r5,#NBLIGNES blt 1b
mov r4,#0 @ loop indice mov r5,#0 @ total ldr r3,iAdrtiValues @ table values address
2:
mul r6,r5,r7 add r6,r4,lsl #2 ldr r0,[r3,r6] ldr r1,iAdrsMessValeur @ display value bl conversion10 @ call conversion decimal mov r1,#0 ldr r0,iAdrsMessResult strb r1,[r0,#4] ldr r0,iAdrsMessResult bl affichageMess @ display message ldr r0,[r3,r6] cmp r0,#MAXVALUE beq 3f add r4,#1 cmp r4,#NBVALUECOL blt 2b ldr r0,iAdrszCarriageReturn bl affichageMess @ display message mov r4,#0 add r5,#1 cmp r5,#NBLIGNES blt 2b b 100f
3:
ldr r0,iAdrszCarriageReturn bl affichageMess @ display message
100: @ standard end of the program
mov r0, #0 @ return code mov r7, #EXIT @ request to exit program svc #0 @ perform the system call
iAdrsMessValeur: .int sMessValeur iAdrszCarriageReturn: .int szCarriageReturn iAdrsMessResult: .int sMessResult iAdrtiValues: .int tiValues
/******************************************************************/ /* display text with size calculation */ /******************************************************************/ /* r0 contains the address of the message */ affichageMess:
push {r0,r1,r2,r7,lr} @ save registres mov r2,#0 @ counter length
1: @ loop length calculation
ldrb r1,[r0,r2] @ read octet start position + index cmp r1,#0 @ if 0 its over addne r2,r2,#1 @ else add 1 in the length bne 1b @ and loop @ so here r2 contains the length of the message mov r1,r0 @ address message in r1 mov r0,#STDOUT @ code to write to the standard output Linux mov r7, #WRITE @ code call system "write" svc #0 @ call systeme pop {r0,r1,r2,r7,lr} @ restaur des 2 registres */ bx lr @ return
/******************************************************************/ /* Converting a register to a decimal unsigned */ /******************************************************************/ /* r0 contains value and r1 address area */ /* r0 return size of result (no zero final in area) */ /* area size => 11 bytes */ .equ LGZONECAL, 10 conversion10:
push {r1-r4,lr} @ save registers mov r3,r1 mov r2,#LGZONECAL
1: @ start loop
bl divisionpar10U @ unsigned r0 <- dividende. quotient ->r0 reste -> r1 add r1,#48 @ digit strb r1,[r3,r2] @ store digit on area cmp r0,#0 @ stop if quotient = 0 subne r2,#1 @ else previous position bne 1b @ and loop @ and move digit from left of area mov r4,#0
2:
ldrb r1,[r3,r2] strb r1,[r3,r4] add r2,#1 add r4,#1 cmp r2,#LGZONECAL ble 2b @ and move spaces in end on area mov r0,r4 @ result length mov r1,#' ' @ space
3:
strb r1,[r3,r4] @ store space in area add r4,#1 @ next position cmp r4,#LGZONECAL ble 3b @ loop if r4 <= area size
100:
pop {r1-r4,lr} @ restaur registres bx lr @return
/***************************************************/ /* division par 10 unsigned */ /***************************************************/ /* r0 dividende */ /* r0 quotient */ /* r1 remainder */ divisionpar10U:
push {r2,r3,r4, lr} mov r4,r0 @ save value //mov r3,#0xCCCD @ r3 <- magic_number lower raspberry 3 //movt r3,#0xCCCC @ r3 <- magic_number higter raspberry 3 ldr r3,iMagicNumber @ r3 <- magic_number raspberry 1 2 umull r1, r2, r3, r0 @ r1<- Lower32Bits(r1*r0) r2<- Upper32Bits(r1*r0) mov r0, r2, LSR #3 @ r2 <- r2 >> shift 3 add r2,r0,r0, lsl #2 @ r2 <- r0 * 5 sub r1,r4,r2, lsl #1 @ r1 <- r4 - (r2 * 2) = r4 - (r0 * 10) pop {r2,r3,r4,lr} bx lr @ leave function
iMagicNumber: .int 0xCCCCCCCD /***************************************************/ /* Generation random number */ /***************************************************/ /* r0 contains limit */ genereraleas:
push {r1-r4,lr} @ save registers ldr r4,iAdriGraine ldr r2,[r4] ldr r3,iNbDep1 mul r2,r3,r2 ldr r3,iNbDep1 add r2,r2,r3 str r2,[r4] @ maj de la graine pour l appel suivant cmp r0,#0 beq 100f mov r1,r0 @ divisor mov r0,r2 @ dividende bl division mov r0,r3 @ résult = remainder
100: @ end function
pop {r1-r4,lr} @ restaur registers bx lr @ return
/*****************************************************/ iAdriGraine: .int iGraine iNbDep1: .int 0x343FD iNbDep2: .int 0x269EC3 /***************************************************/ /* integer division unsigned */ /***************************************************/ division:
/* r0 contains dividend */ /* r1 contains divisor */ /* r2 returns quotient */ /* r3 returns remainder */ push {r4, lr} mov r2, #0 @ init quotient mov r3, #0 @ init remainder mov r4, #32 @ init counter bits b 2f
1: @ loop
movs r0, r0, LSL #1 @ r0 <- r0 << 1 updating cpsr (sets C if 31st bit of r0 was 1) adc r3, r3, r3 @ r3 <- r3 + r3 + C. This is equivalent to r3 ? (r3 << 1) + C cmp r3, r1 @ compute r3 - r1 and update cpsr subhs r3, r3, r1 @ if r3 >= r1 (C=1) then r3 <- r3 - r1 adc r2, r2, r2 @ r2 <- r2 + r2 + C. This is equivalent to r2 <- (r2 << 1) + C
2:
subs r4, r4, #1 @ r4 <- r4 - 1 bpl 1b @ if r4 >= 0 (N=0) then loop pop {r4, lr} bx lr
</lang>
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>
Applesoft BASIC
<lang gwbasic> 1 C = 5
2 R = 4 3 C = C - 1:R = C - 1: DIM A(C,R) 4 FOR J = 0 TO R: FOR I = 0 TO C:N = N + 1:A(I,J) = N: NEXT I,J 5 FOR J = 0 TO R: FOR I = 0 TO C:X = INT ( RND (1) * C):Y = INT ( RND (1) * R):N = A(I,J):A(I,J) = A(X,Y):A(X,Y) = N: NEXT I,J 6 FOR J = 0 TO R 7 FOR I = 0 TO C 8 PRINT S$A(I,J);:S$ = " " 9 IF A(I,J) < > 20 THEN NEXT I,J</lang>
Commodore BASIC
We should END gracefully. (The Sinclair example below will produce an error on any Commodore machine.)
Also... What if no 20 is ever found?
<lang CommodoreBASICv2> 10 dim a$(20,20):print "initializing...":print 20 for r=1 to 20:for c=1 to 20 30 a$(r,c)=chr$(int(rnd(1)*20)+1) 40 next c,r 50 rem now search array 60 for r=1 to 20:for c=1 to 20 70 e=asc(a$(r,c)) 80 print "(";r;","c;") =";e 90 if e=20 then print "found 20. stopping search.":end 100 next c,r 110 print "search complete. no 20 found.":end </lang>
Sinclair ZX81 BASIC
Works with 1k of RAM.
A couple of points to note: (1) since the values we want are small enough to fit into an unsigned byte, we cast them to characters and store them in an array of strings—thereby using only a fifth of the storage space that an array of numbers would take up; (2) the GOTO
statement in line 100 breaks out of both the enclosing loops and also, since its target is higher than any line number in the program, causes execution to terminate normally.
<lang basic> 10 DIM A$(20,20)
20 FOR I=1 TO 20 30 FOR J=1 TO 20 40 LET A$(I,J)=CHR$ (1+INT (RND*20)) 50 NEXT J 60 NEXT I 70 FOR I=1 TO 20 80 FOR J=1 TO 20 90 PRINT CODE A$(I,J);" ";
100 IF CODE A$(I,J)=20 THEN GOTO 130 110 NEXT J 120 NEXT I</lang>
BASIC256
<lang BASIC256>dim a(20, 20)
for i = 0 to 19 for j = 0 to 19 a[i, j] = int(rand * 20) + 1 next j next i
for i = 0 to 19 for j = 0 to 19 print a[i, j];" "; if a[i, j] = 20 then end next j next i
end</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 PRINT "row "; row%, "col ";col%, "value "; array(row%,col%) IF array(row%,col%) = 20 EXIT FOR row% NEXT NEXT row%
</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>
Using break, the preferred alternative to goto <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) break; } if (a[i][j] == 20) break; printf("\n"); } 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, 21) + 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>
Same using Linq :
<lang csharp>using System;
using System.Collections.Generic;
using System.Linq;
class Program {
static void Main(string[] args) { int[,] a = new int[10, 10]; Random r = new Random();
// prepare linq statement with two 'from' which makes nested loop var pairs = from i in Enumerable.Range(0, 10) from j in Enumerable.Range(0, 10) select new { i = i, j = j};
// iterates through the full nested loop with a sigle foreach statement foreach (var p in pairs) { a[p.i, p.j] = r.Next(0, 21) + 1; }
// iterates through the nested loop until find element = 20 pairs.Any(p => { Console.Write(" {0}", a[p.i, p.j]); return a[p.i, p.j] == 20; }); Console.WriteLine(); }
}</lang>
C++
Lambda call:
<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> Goto statement:
<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; if (col == 20) goto out; } cout << endl; } out:
return 0;
}</lang>
Chapel
<lang chapel>use Random;
var nums:[1..10, 1..10] int; var rnd = new RandomStream();
[ n in nums ] n = floor(rnd.getNext() * 21):int; delete rnd;
// this shows a clumsy explicit way of iterating, to actually create nested loops: label outer for i in nums.domain.dim(1) {
for j in nums.domain.dim(2) { write(" ", nums(i,j)); if nums(i,j) == 20 then break outer; } writeln();
}</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>
COBOL
<lang cobol> IDENTIFICATION DIVISION.
PROGRAM-ID. Nested-Loop.
DATA DIVISION. LOCAL-STORAGE SECTION. 78 Table-Size VALUE 10. 01 Table-Area. 03 Table-Row OCCURS Table-Size TIMES INDEXED BY Row-Index. 05 Table-Element PIC 99 OCCURS Table-Size TIMES INDEXED BY Col-Index.
01 Current-Time PIC 9(8). PROCEDURE DIVISION.
- *> Seed RANDOM.
ACCEPT Current-Time FROM TIME MOVE FUNCTION RANDOM(Current-Time) TO Current-Time
- *> Put random numbers in the table.
- *> The AFTER clause is equivalent to a nested PERFORM VARYING
- *> statement.
PERFORM VARYING Row-Index FROM 1 BY 1 UNTIL Table-Size < Row-Index AFTER Col-Index FROM 1 BY 1 UNTIL Table-Size < Col-Index COMPUTE Table-Element (Row-Index, Col-Index) = FUNCTION MOD((FUNCTION RANDOM * 1000), 20) + 1 END-PERFORM
- *> Search through table for 20.
- *> Using proper nested loops.
PERFORM VARYING Row-Index FROM 1 BY 1 UNTIL Table-Size < Row-Index PERFORM VARYING Col-Index FROM 1 BY 1 UNTIL Table-Size < Col-Index IF Table-Element (Row-Index, Col-Index) = 20 EXIT PERFORM ELSE DISPLAY Table-Element (Row-Index, Col-Index) END-IF END-PERFORM END-PERFORM
GOBACK .</lang>
ColdFusion
<lang cfm> <Cfset RandNum = 0> <Cfloop condition="randNum neq 20">
<Cfloop from="1" to="5" index="i"> <Cfset randNum = RandRange(1, 20)> <Cfoutput>#randNum# </Cfoutput> <Cfif RandNum eq 20><cfbreak></Cfif> </Cfloop>
</Cfloop> </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>
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.
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>
Dyalect
There is no direct way to break out of a nested loop in Dyalect, goto
is also not supported, however the desired effect can be achieved by placing a nested loop in an expression context and make it return true
if we need to break out of the parent loop:
<lang dyalect>let array = [[2, 12, 10, 4], [18, 11, 20, 2]]
for row in array {
break when { for element in row { print("\(element)") if element == 20 { break true } } }
} print("*Done")</lang>
- Output:
2 12 10 4 18 11 20 *Done
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>
EchoLisp
<lang lisp> (lib 'math) ;; for 2D-arrays (define array (build-array 42 42 (lambda(i j) (1+ (random 20)))))
→ array
(for* ((row array) (aij row)) (write aij) #:break (= aij 20))
→ 9 8 11 1 14 11 1 9 16 1 10 5 5 6 5 4 13 17 14 13 6 10 16 4 8 5 1 17 16 19 4 6 18 1 15 3 4 13 19 6 12 5 5 17 19 16 3 7 2 15 16 14 16 16 19 18 14 16 6 18 14 17 20
</lang>
Elixir
<lang elixir>defmodule Loops do
def nested do list = Enum.shuffle(1..20) |> Enum.chunk(5) IO.inspect list, char_lists: :as_lists try do nested(list) catch :find -> IO.puts "done" end end def nested(list) do Enum.each(list, fn row -> Enum.each(row, fn x -> IO.write "#{x} " if x == 20, do: throw(:find) end) IO.puts "" end) end
end
Loops.nested</lang>
- Sample output:
[[3, 11, 4, 15, 18], [8, 7, 12, 17, 9], [6, 20, 14, 1, 16], [2, 5, 10, 19, 13]] 3 11 4 15 18 8 7 12 17 9 6 20 done
used Enum.any? <lang elixir>list = Enum.shuffle(1..20) |> Enum.chunk(5) IO.inspect list, char_lists: :as_lists Enum.any?(list, fn row ->
IO.puts "" Enum.any?(row, fn x -> IO.write "#{x} " x == 20 end)
end) IO.puts "done"</lang>
- Sample output:
[[17, 15, 18, 14, 16], [5, 11, 10, 4, 2], [8, 20, 7, 19, 1], [6, 9, 3, 12, 13]] 17 15 18 14 16 5 11 10 4 2 8 20 done
Erlang
<lang Erlang> -module( loops_nested ).
-export( [task/0] ).
task() ->
Size = 20, Two_dimensional_array = [random_array(Size) || _X <- lists:seq(1, Size)], print_until_found( [], 20, Two_dimensional_array ).
print_until_found( [], N, [Row | T] ) -> print_until_found( print_until_found_row(N, Row), N, T ); print_until_found( _Found, _N, _Two_dimensional_array ) -> io:fwrite( "~n" ).
print_until_found_row( _N, [] ) -> []; print_until_found_row( N, [N | T] ) -> [N | T]; print_until_found_row( N, [H | T] ) ->
io:fwrite( "~p ", [H] ), print_until_found_row( N, T ).
random_array( Size ) -> [random:uniform(Size) || _X <- lists:seq(1, Size)]. </lang>
ERRE
<lang ERRE> DIM A%[10,10] ! in declaration part ............. PRINT(CHR$(12);) !CLS FOR ROW=1 TO 10 DO
FOR COL=1 TO 10 DO A%[ROW,COL]=INT(RND(1)*20)+1 ! INT and RND are ERRE predeclared functions ! RND generates random numbers between 0 and 1 END FOR
END FOR
FOR ROW=1 TO 10 DO
FOR COL=1 TO 10 DO PRINT(A%[ROW,COL]) EXIT IF A%[ROW,COL]=20 END FOR EXIT IF A%[ROW,COL]=20 ! EXIT breaks the current loop only: you must repeat it, ! use a boolean variable or a GOTO label statement
END FOR </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.
F#
<lang fsharp> //Nigel Galloway: November 10th., 2017 let n = System.Random() let g = Array2D.init 8 8 (fun _ _ -> 1+n.Next()%20) Array2D.iter (fun n -> printf "%d " n) g; printfn "" g |> Seq.cast<int> |> Seq.takeWhile(fun n->n<20) |> Seq.iter (fun n -> printf "%d " n) </lang>
- Output:
3 7 5 8 7 5 12 14 6 10 7 8 4 8 10 2 12 16 9 19 14 10 1 1 14 2 8 18 1 1 6 19 5 16 15 16 11 19 19 17 3 9 9 15 14 12 20 18 14 8 5 12 20 14 5 14 7 5 15 13 5 15 14 13 3 7 5 8 7 5 12 14 6 10 7 8 4 8 10 2 12 16 9 19 14 10 1 1 14 2 8 18 1 1 6 19 5 16 15 16 11 19 19 17 3 9 9 15 14 12
Factor
Whenever you need to break out of iteration early in Factor, you almost always want to use find
. find
is a tail-recursive combinator that searches a sequence. Its base case is satisfied when its predicate quotation returns t
.
<lang factor>USING: io kernel math.ranges prettyprint random sequences ;
10 [ 20 [ 20 [1,b] random ] replicate ] replicate ! make a table of random values [ [ dup pprint bl 20 = ] find nl drop ] find 2drop ! print values until 20 is found</lang>
Alternatively, calling return
from inside a with-return
quotation allows one to break out of the quotation. This is similar to the way other languages do things: with an explicit break. This is less elegant in Factor because it introduces an additional quotation and involves continuations when they aren't strictly necessary (resulting in slower execution than find
).
<lang factor>USING: continuations io kernel math.ranges prettyprint random
sequences ;
10 [ 20 [ 20 [1,b] random ] replicate ] replicate ! make a table of random values [
[ [ dup pprint bl 20 = [ return ] when ] each nl ] each ! print values until 20 is found
] with-return drop</lang>
- Output:
19 5 19 14 15 14 17 16 4 11 17 3 19 10 2 1 8 13 2 6 15 7 12 19 3 7 4 10 7 17 6 1 10 15 6 3 18 18 4 11 20
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 come with a random number generator, but it is C easy enough to type "fortran 77 random number generator" into your C preferred search engine and to copy and paste what you find. C The 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
Here the special feature is that later Fortran allows loops to be labelled (with "outer" in this example) on their first and last statements. Any EXIT or CYCLE statements can then mention the appropriate label so as to be clear just which loop is involved, otherwise the assumption is the innermost loop only. And no "GO TO" statements need appear. <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
FreeBASIC
<lang freebasic>' FB 1.05.0 Win64
Randomize Dim a(1 To 20, 1 To 20) As Integer For i As Integer = 1 To 20
For j As Integer = 1 To 20 a(i, j) = Int(Rnd * 20) + 1 Next j
Next i
For i As Integer = 1 To 20
For j As Integer = 1 To 20 Print Using "##"; a(i, j); Print " "; If a(i, j) = 20 Then Exit For, For Exits both for loops Next j Print
Next i
Print Print "Press any key to quit" Sleep</lang>
Sample output :
- Output:
13 3 16 13 16 11 15 19 10 5 12 7 17 1 6 11 2 19 11 11 12 17 20
Frink
<lang frink>array = new array[[10,10], {|x,y| random[1,20]}]
println["array is:\n" + formatTable[array, "right"] + "\n"]
[rows,cols] = array.dimensions[]
ROW: for r = 0 to rows-1
for c = 0 to cols-1 { print[array@r@c + " " ] if array@r@c == 20 break ROW }</lang>
- Output:
array is: 19 1 15 14 10 20 13 4 20 14 12 2 4 16 17 4 1 8 20 18 12 17 2 11 13 14 9 18 4 16 15 14 1 13 16 9 8 10 3 12 14 1 14 5 17 20 5 6 15 3 17 10 6 16 1 2 4 14 2 6 14 7 1 13 7 16 10 3 11 11 5 3 18 15 20 18 16 5 11 7 19 18 4 8 7 18 11 14 2 3 10 17 11 10 20 18 14 20 15 14 19 1 15 14 10 20
Gambas
Click this link to run this code <lang gambas>Public Sub Main() Dim siArray As New Short[5, 5] Dim siCount0, siCount1 As Short Dim bBreak As Boolean
For siCount0 = 0 To 4
For siCount1 = 0 To 4 siArray[siCount0, siCount1] = Rand(1, 20) siArray[siCount0, siCount1] = Rand(1, 20) Next
Next
For siCount0 = 0 To 4
For siCount1 = 0 To 4 If siArray[siCount0, siCount1] = 20 Then bBreak = True Break Endif Next If bBreak Then Break
Next
Print "Row " & Str(siCount0) & " column " & Str(siCount1) & " = 20"
End</lang> Output:
Row 5 column 4 = 20
GAP
<lang gap># You can't break an outer loop unless you return from the whole function. n := 40; a := List([1 .. n], i -> List([1 .. n], j -> Random(1, 20)));;
Find := function(a, x)
local i, j, n; n := Length(a); for i in [1 .. n] do for j in [1 .. n] do if a[i][j] = x then return [i, j]; fi; od; od; return fail;
end;
Find(a, 20);</lang>
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 :: (a -> Bool) -> [a] -> [a] breakIncl p = uncurry ((. take 1). (++)). break p
taskLLB k = map (breakIncl (==k)). breakIncl (k `elem`)</lang>
- Example:
<lang haskell>
- Main> mapM_ (mapM_ print) $ taskLLB 20 [[2,6,17,5,14],[1,9,11,18,10],[13,20,8,7,4],[16,15,19,3,12]]
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 -- the underlying implementation implements a rich set of highly optimized special case loops. That said, general case loops can be used and can be a good choice when the operations provided by the primitives need to be severely pruned.
So, here's how the problem statement could be solved, without explicit loops (there's a conceptual nested loop and a short circuited search loop implemented within these primitives): <lang J>use=: ({.~ # <. 1+i.&20)@:,</lang> Here's how the problem could be solved, using loops: <lang J>doubleLoop=: Template:For row. i.</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>
In a functional idiom of JavaScript, however, we can not use a loop statement, as statements return no value and can not be composed within other functional expressions. Functional JavaScript often replaces a loop with a map or fold. In this case, we can achieve the same task by defining the standard list-processing function takeWhile, which terminates when a condition returns true.
We can then search the groups in the nested array by nesting takeWhile inside itself, and finally terminate when the 20 is found by one further application of takeWhile.
Using the same data as above, and returning the trail of numbers up to twenty from a nested and composable expression:
<lang JavaScript>var lst = [[2, 12, 10, 4], [18, 11, 9, 3], [14, 15, 7, 17], [6, 19, 8, 13], [1,
20, 16, 5]];
var takeWhile = function (lst, fnTest) {
'use strict'; var varHead = lst.length ? lst[0] : null;
return varHead ? ( fnTest(varHead) ? [varHead].concat( takeWhile(lst.slice(1), fnTest) ) : [] ) : [] },
// The takeWhile function terminates when notTwenty(n) returns false notTwenty = function (n) { return n !== 20; },
// Leftward groups containing no 20 // takeWhile nested within takeWhile lstChecked = takeWhile(lst, function (group) { return takeWhile( group, notTwenty ).length === 4; });
// Return the trail of numbers preceding 20 from a composable expression
console.log(
// Numbers before 20 in a group in which it was found lstChecked.concat( takeWhile( lst[lstChecked.length], notTwenty ) ) // flattened .reduce(function (a, x) { return a.concat(x); }).join('\n')
);</lang>
Output: <lang JavaScript>2 12 10 4 18 11 9 3 14 15 7 17 6 19 8 13 6 19 8 13 1</lang>
jq
jq has a `break` statement for breaking out of nested loops, and in this entry, it is used in the following function:
<lang jq># Given an m x n matrix,
- produce a stream of the matrix elements (taken row-wise)
- up to but excluding the first occurrence of $max
def stream($max):
. as $matrix | length as $m | (.[0] | length) as $n | label $ok | {i: range(0;$m), j: range(0;$n)} | $matrix[.i][.j] as $m | if $m == $max then break $ok else $m end ;</lang>
The nesting above could be made more visually explicit, for example, by using the equivalent form:
range(0;$m) as $i | range(0;$n) as $j
but the previous formulation illustrates a concise alternative.
To generate the random matrix, and to accomplish the "pretty-printing" component of the task, the following function for converting a stream to an array of arrays is useful:
<lang jq># Create an array of arrays by using the items in the stream, s,
- to create successive rows, each row having at most n items.
def reshape(s; n):
reduce s as $s ({i:0, j:0, matrix: []}; .matrix[.i][.j] = $s | if .j + 1 == n then .i += 1 | .j = 0 else .j += 1 end) | .matrix;</lang>
Assuming the availability of rand/1 (e.g. as defined below), we can now readily define functions to create the matrix and pretty-print the items as required: <lang jq># Create an m x n matrix filled with numbers in [1 .. max] def randomMatrix(m; n; max):
reshape(limit(m * n; rand(max) + 1); n);
- Present the matrix up to but excluding the first occurrence of $max
def show($m; $n; $max):
reshape( randomMatrix($m; $n; $max) | stream($max); $n)[] ;
- Main program for the problem at hand.
show(20; 4; 20)</lang>
- Output:
Assuming proper placement of PRNG functions as defined below, the following invocation:
$ jq -cn -f program.jq --arg seed 17
produces:
[1,17,19,12] [13,8,18,10] [18,15,3,18] [11,12,3,10] [4,8,1,14] [12,1,10,9] [3,16,19,13] [10,12,13]
PRNG
<lang jq># LCG::Microsoft generates 15-bit integers using the same formula
- as rand() from the Microsoft C Runtime.
- Input: [ count, state, random ]
def next_rand_Microsoft:
.[0] as $count | ((214013 * .[1]) + 2531011) % 2147483648 # mod 2^31 | [$count+1 , ., (. / 65536 | floor) ];
def rand_Microsoft(seed):
[0,seed] | next_rand_Microsoft # the seed is not so random | recurse( next_rand_Microsoft ) | .[2];
- A random integer in [0 ... (n-1)]:
- rand_Microsoft returns an integer in 0 .. 32767
def rand(n): n * (rand_Microsoft($seed|tonumber) / 32768) | trunc;</lang>
Jsish
<lang javascript>/* Loops/Nested in Jsish */ Math.srand(0); var nrows = Math.floor(Math.random() * 4) + 4; var ncols = Math.floor(Math.random() * 6) + 6;
var matrix = new Array(nrows).fill(0).map(function(v, i, a):array { return new Array(ncols).fill(0); } );
var i,j; for (i = 0; i < nrows; i++) for (j = 0; j < ncols; j++) matrix[i][j] = Math.floor(Math.random() * 20) + 1;
/* Labelled break point */ outer_loop: for (i in matrix) {
printf("row %d:", i); for (j in matrix[i]) { printf(" %d", matrix[i][j]); if (matrix[i][j] == 20) { printf("\n"); break outer_loop; } } printf("\n");
} puts(matrix);
/*
!EXPECTSTART!
row 0: 2 18 12 16 14 8 18 15 9 8 row 1: 15 6 8 16 17 12 15 2 10 3 row 2: 11 8 12 20 [ [ 2, 18, 12, 16, 14, 8, 18, 15, 9, 8 ],
[ 15, 6, 8, 16, 17, 12, 15, 2, 10, 3 ], [ 11, 8, 12, 20, 18, 4, 6, 6, 19, 9 ], [ 16, 3, 2, 19, 1, 4, 8, 4, 11, 18 ] ]
!EXPECTEND!
- /</lang>
- Output:
prompt$ jsish -u loopsNested.jsi [PASS] loopsNested.jsi
Julia
<lang Julia> M = [rand(1:20) for i in 1:5, j in 1:10] R, C = size(M)
println("The full matrix is:") println(M, "\n")
println("Find the first 20:") for i in 1:R, j in 1:C
n = M[i,j] @printf "%4d" n if n == 20 println() break elseif j == C println() end
end </lang>
- Output:
The full matrix is: [9 17 10 8 6 10 13 12 7 12 15 14 13 7 8 12 15 2 12 1 8 3 4 14 19 1 3 13 11 15 19 16 18 2 9 3 4 17 16 10 16 4 20 19 8 1 18 14 12 4] Find the first 20: 9 17 10 8 6 10 13 12 7 12 15 14 13 7 8 12 15 2 12 1 8 3 4 14 19 1 3 13 11 15 19 16 18 2 9 3 4 17 16 10 16 4 20
Julia is column ordered, but this program searches in row order to be consistent with the other solutions of this task.
Kotlin
<lang scala>import java.util.Random
fun main(args: Array<String>) {
val r = Random() val a = Array(10) { IntArray(10) { r.nextInt(20) + 1 } } println("array:") for (i in a.indices) println("row $i: " + a[i].asList())
println("search:") Outer@ for (i in a.indices) { print("row $i: ") for (j in a[i].indices) { print(" " + a[i][j]) if (a[i][j] == 20) break@Outer } println() } println()
}</lang>
- Output:
array: row 0: [10, 8, 19, 17, 19, 7, 13, 16, 16, 4] row 1: [6, 2, 6, 1, 11, 10, 2, 8, 1, 14] row 2: [3, 6, 4, 6, 10, 2, 10, 20, 18, 1] row 3: [16, 14, 6, 13, 18, 8, 18, 7, 4, 18] row 4: [14, 10, 13, 11, 2, 17, 16, 19, 1, 1] row 5: [4, 20, 6, 17, 20, 12, 20, 15, 16, 15] row 6: [2, 20, 6, 5, 5, 15, 1, 2, 6, 18] row 7: [14, 6, 8, 10, 12, 8, 12, 3, 14, 10] row 8: [1, 5, 15, 12, 7, 14, 9, 7, 16, 11] row 9: [20, 16, 5, 13, 15, 9, 3, 2, 2, 16] search: row 0: 10 8 19 17 19 7 13 16 16 4 row 1: 6 2 6 1 11 10 2 8 1 14 row 2: 3 6 4 6 10 2 10 20
Lambdatalk
<lang scheme> 1) the A.find function gets a value and a unidimensional array,
then retuns the item matching the value else -1
{def A.find
{def A.find.r {lambda {:val :arr :n :i :acc} {if {> :i :n} then -1 else {if {= :val {A.get :i :arr}} then :i else {A.find.r :val :arr :n {+ :i 1} {A.addlast! :i :acc}}}}}} {lambda {:val :arr} {A.find.r :val :arr {- {A.length :arr} 1} 0 {A.new}}}}
-> A.find
{def A {A.new {S.serie 0 20}}} -> A = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
{A.find 12 {A}} -> 12 // the index {A.find 21 {A}} -> -1 // not found
2) the AA.find function gets a value and a bidimensional array,
then returns the sequence of rows until the row containing the value, and diplays the row containing the value if it exists else displays "the value was not found".
{def AA.find
{def AA.find.r {lambda {:val :arr :n :i} {if {> :i :n} then {br}:val was not found else {if {not {= {A.find :val {A.get :i :arr}} -1}} // call the A.find function on each row then {br}:val was found in {A.get :i :arr} else {br}{A.get :i :arr} {AA.find.r :val :arr :n {+ :i 1}} }}}} {lambda {:val :arr} {AA.find.r :val :arr {- {A.length :arr} 1} 0}}}
-> AA.find
3) testing
3.1) the rn function returns a random integer between 0 and n {def rn {lambda {:n} {round {* :n {random}}}}} -> rn
3.2) creating a bidimensional array containing random integers between 0 and 20 {def AA {A.new {A.new {rn 20} {rn 20} {rn 20} {rn 20} {rn 20}}
{A.new {rn 20} {rn 20} {rn 20} {rn 20} {rn 20}} {A.new {rn 20} {rn 20} {rn 20} {rn 20} {rn 20}} {A.new {rn 20} {rn 20} {rn 20} {rn 20} {rn 20}}}}
-> AA = [[9,4,10,14,1],[4,12,7,18,13],[7,13,19,12,11],[18,4,2,14,15]]
3.3) calling with a value which can be in the array {AA.find 12 {AA}} -> [9,4,10,14,1] 12 was found in [4,12,7,18,13]
3.4) calling with a value outside of the array {AA.find 21 {AA}} -> [9,4,10,14,1] [4,12,7,18,13] [7,13,19,12,11] [18,4,2,14,15] 21 was not found </lang>
Lasso
<lang Lasso>local(a) = array(
array(2, 12, 10, 4), array(18, 11, 9, 3), array(14, 15, 7, 17), array(6, 19, 8, 13), array(1, 20, 16, 5)
)
// Query expression with i in delve(#a) do {
stdoutnl(#i) #i == 20 ? return
}
// Nested loops
- a->foreach => {
#1->foreach => { stdoutnl(#1) #1 == 20 ? return }
}</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>
Lingo
<lang lingo>-- create two-dimensional array with random numbers a = [] repeat with i = 1 to 20
a[i] = [] repeat with j = 1 to 20 a[i][j] = random(20) end repeat
end repeat
-- iterate over rows and columns, print value, exit both loops if it's 20 repeat with i = 1 to 20
repeat with j = 1 to 20 v = a[i][j] put v if v=20 then exit repeat end repeat if v=20 then exit repeat
end repeat</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>
LiveCode
<lang LiveCode>repeat with i = 1 to 10
repeat with j = 1 to 10 put random(20) into aNums[i,j] end repeat
end repeat
repeat with i = 1 to 10
repeat with j = 1 to 10 if aNums[i,j] = 20 then put true into exitLoop exit repeat end if end repeat if exitLoop then exit repeat
end repeat
if exitLoop then
put "20 found in" && i & comma & j
else
put "20 not found"
end if</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>
M2000 Interpreter
We can use a number as a label, so instead of using "then goto there" we can use "then 1000" if label is 1000.
No numeric labels may have only comments in same line.
Numeric labels may have 1 to 5 digits, including leading zeros. So 00010 is label 10. Numeric labels have no : after, but if we place one then this isn't fault, because : is a statement separator.
In this example we execute nested for two times, using a third for.
<lang M2000 Interpreter>
Module Checkit {
Dim A(10,10)<<Random(1, 20) For k=1 to 2 { For i=0 to 9 { For j=0 to 9 { Print A(i,j) if A(i,j)=20 then goto there } } there: Print "...ok", k }
} Checkit </lang>
Maple
<lang Maple>(m,n) := LinearAlgebra:-Dimensions(M): for i from 1 to m do
for j from 1 to n do print(M[i,j]); if M[i,j] = 20 then (i,j):=m,n; next; end if; end do;
end do:</lang>
Mathematica /Wolfram Language
<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>
MAXScript
<lang MAXScript> fn scan_Nested arr = ( for subArray in arr where classof subArray == Array do ( for item in subArray do ( print item as string if item == 20 do return OK ) ) ) </lang>
Example: <lang MAXScript> testArray = #(#(1,5,2,19),#(11,20,7,2)) scan_nested testArray
- (#(1, 5, 2, 19), #(11, 20, 7, 2))
1 5 2 19 11 20 OK
</lang>
Microsoft Small Basic
<lang smallbasic>For row = 0 To 10
For col = 0 To 10 array[row][col] = Math.GetRandomNumber(20) EndFor
EndFor For row = 0 To 10
For col = 0 To 10 TextWindow.WriteLine("row "+row+" col "+col+" value "+array[row][col]) If array[row][col] = 20 Then Goto exit_for_row EndIf EndFor
EndFor exit_for_row:</lang>
- Output:
row 0 col 0 value 11 row 0 col 1 value 19 row 0 col 2 value 19 row 0 col 3 value 1 row 0 col 4 value 20
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,
Neko
<lang ActionScript>/**
Loops/Nested in Neko Tectonics: nekoc loops-nested.neko neko loops-nested.neko
- /
var random = $loader.loadprim("std@random_new", 0)(); var random_int = $loader.loadprim("std@random_int", 2);
var values = $amake(10); var row = 0; var col = 0;
while row < 10 {
values[row] = $amake(10); col = 0; while col < 10 { values[row][col] = random_int(random, 20) + 1; col += 1; } row += 1;
}
/* Look for a 20 */ /*
To break out of nested loops, (without using labels and $goto), Neko needs the value of the inner loop(s). The break statement sets the return value of a loop expression. Without a break, the value of a loop expression is unspecified.
- /
var inner; row = 0; while row < 10 {
col = 0; inner = while col < 10 { $print("values[", row, "][", col, "] = ", values[row][col], "\n"); if values[row][col] == 20 break true; col += 1; } if $istrue(inner) break; row += 1;
}</lang>
- Output:
prompt$ nekoc loops-nested.neko prompt$ neko loops-nested values[0][0] = 17 values[0][1] = 1 values[0][2] = 8 values[0][3] = 5 values[0][4] = 18 values[0][5] = 17 values[0][6] = 17 values[0][7] = 19 values[0][8] = 2 values[0][9] = 1 values[1][0] = 11 values[1][1] = 4 values[1][2] = 16 values[1][3] = 11 values[1][4] = 12 values[1][5] = 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 x 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) 14.217 the REXX program run with Regina 10.109 the REXX program run with ooRexx
NewLISP
<lang NewLISP>(let (a (array 10 10))
(dotimes (i 10) (dotimes (j 10) (setf (a i j) (rand 21)))) (catch (dotimes (i 10)
(dotimes (j 10) (print (a i j)) (print " ") (if (= 20 (a i j)) (throw))))))</lang>
Nim
<lang nim>import random, strutils
const ArrSize = 10
var a: array[ArrSize, array[ArrSize, int]] var s = ""
randomize() # Different results each time this runs.
- Initialize using loops on items rather than indexes.
for row in a.mitems:
for item in row.mitems: item = rand(1..20)
block outer:
# Loop using indexes. for i in 0..<ArrSize: for j in 0..<ArrSize: if a[i][j] < 10: s.add(' ') addf(s, "$#", $a[i][j]) if a[i][j] == 20: break outer s.add(", ") s.add('\n')
echo s</lang>
- Output:
9, 16, 3, 18, 4, 17, 2, 16, 7, 6, 1, 6, 1, 11, 9, 8, 12, 7, 19, 8, 13, 16, 4, 5, 2, 20
NS-HUBASIC
<lang NS-HUBASIC>10 DIM A(20) 20 FOR I=1 TO 20 30 A(I)=RND(20)+1 40 NEXT 50 PRINT "THE FULL LIST:"; 60 FOR I=1 TO 20 70 PRINT A(I); 80 NEXT 90 PRINT 100 PRINT "THE FULL LIST UP TO THE FIRST ";"INSTANCE OF 20:"; 110 FOR I=1 TO 20 120 PRINT A(I); 130 IF A(I)=20 THEN END 140 NEXT</lang>
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>
Pascal
<lang pascal>program LoopNested; uses SysUtils; const Ni=10; Nj=20; var
tab: array[1..Ni,1..Nj] of Integer; i, j: Integer;
label loopend; begin
for i := 1 to Ni do for j := 1 to Nj do tab[i,j]:=random(20)+1; for i := 1 to Ni do begin for j := 1 to Nj do begin WriteLn(tab[i,j]); if tab[i,j]=20 then goto loopend end end;
loopend: end.</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>
Phix
use an explicit flag
constant s = sq_rand(repeat(repeat(20,20),20)) integer found = 0 for i=1 to 20 do for j=1 to 20 do printf(1,"%d",s[i][j]) if s[i][j]=20 then found = 1 exit end if printf(1,", ") end for printf(1,"\n") if found then exit end if end for
alternatively you can use a procedure
procedure till20() for i=1 to 20 do for j=1 to 20 do printf(1,"%d",s[i][j]) if s[i][j]=20 then return end if printf(1,", ") end for printf(1,"\n") end for end procedure till20() printf(1,"\n")
or a goto
procedure till20() for i=1 to 20 do for j=1 to 20 do printf(1,"%d",s[i][j]) if s[i][j]=20 then goto :done end if printf(1,", ") end for printf(1,"\n") end for ::done printf(1,"\n") end procedure till20()
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>
Pike
Pike does not have a generic goto, but break is a special case in that you can specify labels and break several levels of loop. In practise this is extremely seldom used in favor of using a state variable or containing the nest in a function that you return from in the inner loop. However it's there if you want it:
<lang> int main() {
// enumerate() normally returns a linearly enumerated array, but // allows for the forth argument to specify a function that will // be called and return the value that should be in each cell. We // create an anonymous function (lambda) that just returns a // random value. array a = ({}); for(int i=0; i<20; i++) a += ({ enumerate( 20, 1, 1, lambda(){return random(20)+1;} ) });
// We could use for() and a[x][y] indexing, but foreach is just // shorter and easier to use even if the 2D-array becomes less // obvious. mynestedloops: foreach(a, array inner_a) { foreach(inner_a, int value) { write(value +" "); if(value == 20) break mynestedloops; } } write("\n");
} </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>
Quackery
<lang Quackery> []
5 times [ [] 5 times [ 20 random 1+ join ] nested join ] dup say "Array contains:" cr witheach [ witheach [ echo sp ] cr ] cr say "Array up to item = 20:" cr witheach [ false swap witheach [ dup 20 = iff [ drop not conclude ] else [ echo sp ] ] iff conclude else cr ]</lang>
- Output:
Array contains: 16 9 10 11 6 2 10 14 12 20 19 4 4 3 18 15 20 10 7 3 10 19 14 10 7 Array up to item = 20: 16 9 10 11 6 2 10 14 12
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>
Racket
<lang racket>
- lang racket
(define (scan xss)
(for* ([xs xss] [x xs] #:final (= x 20)) (displayln x)))
(define matrix
(for/list ([x 10]) (for/list ([y 10]) (+ (random 20) 1))))
(scan matrix)</lang>
Raku
(formerly 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>
- 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
REBOL
<lang REBOL>REBOL [ Title: "Loop/Nested" 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
ReScript
<lang ReScript>let m = []
for _ in 0 to 9 {
let n = [] for _ in 0 to 9 { let _ = Js.Array2.push(n, 1 + Js.Math.random_int(0, 20)) } let _ = Js.Array2.push(m, n)
}
try {
for i in 0 to 9 { for j in 0 to 9 { Js.log(m[i][j]) if m[i][j] == 20 { raise(Exit) } } }
} catch { | Exit => Js.log("stop") }</lang>
REXX
Since the two-dimensional array could potentially not be large enough
to contain the target (20), it's possible to not find the target.
Code was added to this REXX program to reflect that possibility and issue an appropriate message (whether the target was found or not).
<lang rexx>/*REXX program loops through a two-dimensional array to search for a '20' (twenty). */
parse arg rows cols targ . /*obtain optional arguments from the CL*/
if rows== | rows=="," then rows=60 /*Rows not specified? Then use default*/
if cols== | cols=="," then cols=10 /*Cols " " " " " */
if targ== | targ=="," then targ=20 /*Targ " " " " " */
w=max(length(rows), length(cols), length(targ)) /*W: used for formatting the output. */
not= 'not' /* [↓] construct the 2─dimension array*/
do row=1 for rows /*ROW is the 1st dimension of array. */ do col=1 for cols /*COL " " 2nd " " " */ @.row.col=random(1, targ) /*create some positive random integers.*/ end /*row*/ end /*col*/
do r=1 for rows /* ◄───────────────── now, search for the target {20}.*/ do c=1 for cols say left('@.'r"."c, 3+w+w) '=' right(@.r.c, w) /*show an array element.*/ if @.r.c==targ then do; not=; leave r; end /*found the targ number?*/ end /*c*/ end /*r*/
say right( space( 'Target' not "found:" ) targ, 33, '─')
/*stick a fork in it, we're all done. */</lang>
output when using the default inputs:
@.1.1 = 19 @.1.2 = 14 @.1.3 = 16 @.1.4 = 8 @.1.5 = 1 @.1.6 = 4 @.1.7 = 11 @.1.8 = 7 @.1.9 = 15 @.1.10 = 16 @.2.1 = 11 @.2.2 = 4 @.2.3 = 3 @.2.4 = 6 @.2.5 = 18 @.2.6 = 7 @.2.7 = 5 @.2.8 = 7 @.2.9 = 2 @.2.10 = 7 @.3.1 = 20 ─────────────────Found target: 20
output when using the input of: 2 2
@.1.1 = 14 @.1.2 = 6 @.2.1 = 13 @.2.2 = 13 ─────────────Target not found: 20
Ring
<lang ring> size = 5 array = newlist(size,size) for row = 1 to size
for col = 1 to size array[row][col] = random(19) + 1 next
next
for row = 1 to size
for col = 1 to size see "row " + row + " col " + col + "value : " + array[row][col] + nl if array[row][col] = 20 exit for row ok next
next
func newlist x, y
if isstring(x) x=0+x ok if isstring(y) y=0+y ok aList = list(x) for t in aList t = list(y) next return aList
</lang> Output:
row 1 col 1 value : 10 row 1 col 2 value : 3 row 1 col 3 value : 8 row 1 col 4 value : 8 row 1 col 5 value : 1 row 2 col 1 value : 3 row 2 col 2 value : 3 row 2 col 3 value : 4 row 2 col 4 value : 6 row 2 col 5 value : 8 row 3 col 1 value : 14 row 3 col 2 value : 12 row 3 col 3 value : 2 row 3 col 4 value : 11 row 3 col 5 value : 9 row 4 col 1 value : 17 row 4 col 2 value : 9 row 4 col 3 value : 19 row 4 col 4 value : 12 row 4 col 5 value : 12 row 5 col 1 value : 7 row 5 col 2 value : 6 row 5 col 3 value : 17 row 5 col 4 value : 5 row 5 col 5 value : 6
Ruby
As the break command only jumps out of the innermost loop,
this task requires Ruby's catch/throw
functionality.
<lang ruby>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
However, for-loops are not very popular. This is more idiomatic ruby, which avoids loops and breaking out of them: <lang ruby>p slices = [*1..20].shuffle.each_slice(4)
slices.any? do |slice|
puts slice.any? do |element| print "#{element} " element == 20 end
end puts "done"</lang>
- Output:
#<Enumerator: [1, 4, 9, 13, 15, 10, 3, 5, 14, 17, 18, 8, 2, 12, 6, 19, 20, 11, 7, 16]:each_slice(4)> 1 4 9 13 15 10 3 5 14 17 18 8 2 12 6 19 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>
Rust
<lang rust>use rand::Rng;
extern crate rand;
fn main() {
let mut matrix = [[0u8; 10]; 10]; let mut rng = rand::thread_rng();
for row in matrix.iter_mut() { for item in row.iter_mut() { *item = rng.gen_range(0, 21); } }
'outer: for row in matrix.iter() { for &item in row.iter() { print!("{:2} ", item); if item == 20 { break 'outer } } println!(); }
}</lang>
- Output:
5 3 8 18 13 2 5 13 6 17 5 14 20
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>
S-BASIC
S-BASIC doesn't have a BREAK or EXIT statement for early termination of a loop, so the most straight-forward approach is to jump out using a GOTO. But since S-BASIC doesn't allow GOTOs from a FOR..NEXT loop, we have to use WHILE..DO instead. <lang BASIC> $constant ROWS = 10 $constant COLUMNS = 10 $constant MAXVAL = 20
var i, j = integer dim integer table(ROWS, COLUMNS)
rem - populate table using nested FOR..NEXT loops
for i=1 to ROWS
for j=1 to COLUMNS table(i, j) = int(rnd(1) * MAXVAL) + 1 next j
next i
rem - show results using nested WHILE..DO loops
i = 1 while i <= ROWS do
begin j = 1 while j <= COLUMNS do begin print using "## "; table(i, j); if table(i, j) = MAXVAL then goto 0done j = j + 1 end print i = i + 1 end
comment
Although S-BASIC allows alphanumeric line numbers as the target of a GOTO or GOSUB statement, the first "digit" must in fact be a number, as shown here.
end
0done if i > ROWS then print "target value"; MAXVAL; " not found!"
end </lang>
- Output:
1 2 7 20
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>
- 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>
Scilab
<lang>ni=3;nj=4 t=int(rand(ni,nj)*20)+1 for i=1:ni
for j=1:nj printf("%2d ",t(i,j)) if t(i,j)==11 then break; end end printf("\n") if t(i,j)==11 then break; end
end</lang>
- Output:
5 18 19 8 5 14 5 6 5 7 7 12
Seed7
<lang seed7>$ include "seed7_05.s7i";
const proc: main is func
local var integer: i is 0; var integer: j is 0; var array array integer: a is 10 times 10 times 0; const EXCEPTION: FOUND20 is enumlit; begin for i range 1 to 10 do for j range 1 to 10 do a[i][j] := rand(1, 20); end for; end for; block for i range 1 to 10 do for j range 1 to 10 do write(a[i][j] lpad 2 <& ", "); if a[i][j] = 20 then raise FOUND20; end if; end for; writeln; end for; exception catch FOUND20: writeln; end block; end func;</lang>
- Output:
15, 10, 5, 9, 10, 13, 1, 9, 11, 10, 5, 6, 10, 13, 4, 13, 11, 12, 2, 4, 4, 16, 20,
Sidef
<lang ruby>var arr = 10.of{ 10.of{ 20.irand + 1 } }
for row in arr {
for num in row { "%3d".printf(num); num == 20 && goto :OUT } print "\n"
} @:OUT
print "\n"</lang>
- Output:
9 17 14 17 17 7 1 3 9 18 1 12 1 19 9 5 1 17 19 3 17 2 18 12 15 10 8 13 13 14 12 16 13 13 2 11 3 15 2 4 15 15 8 11 5 2 1 16 8 13 17 3 1 1 8 12 4 20
Smalltalk
Notice that the original answer (see below) was wrong (never say never say never...).
it looks a bit wierd, but here is: loopWithExit
<lang smalltalk>|i|
i := 1. [:exit |
Transcript showCR:i. i == 5 ifTrue:[ exit value:'stopped' ]. i := i + 1.
] loopWithExit</lang> these can also be nested, and exited from the inner loop: <lang smalltalk>|i|
i := 1. [:exit1 |
|j|
j := 0. [:exit2 | Transcript showCR:('i is %1 / j is %2' bindWith:i with:j). j == 5 ifTrue:[ exit2 value: nil ]. i == 5 ifTrue:[ exit1 value: nil ]. j := j + 1. ] loopWithExit. i := i + 1
] loopWithExit</lang> in case your smalltalk does not have it, here's the definition: <lang smalltalk>!Block methodsFor:'looping'! loopWithExit
"the receiver must be a block of one argument. It is evaluated in a loop forever, and is passed a block, which, if sent a value:-message, will exit the receiver block, returning the parameter of the value:-message. Used for loops with exit in the middle."
|exitBlock|
exitBlock := [:exitValue | ^ exitValue]. [true] whileTrue:[ self value:exitBlock ]</lang>
in the same spirit, exits could be added to many other loop constructs. However, this is really only very rarely needed in Smalltalk, because a ^(return) out of a block returns from the enclosing method which usually used to exit early from search utility methods.
There is also valueWithExit, which can be used to get out of a block early and provide an alternative value. Using that, the tasks solution is: <lang smalltalk>|v result|
v := 1 to:20 collect:[:i |
1 to:20 collect:[:j | Random nextIntegerBetween:1 and:20 ] ].
result :=
[:exit | 1 to:20 do:[:row | 1 to:20 do:[:col | |element|
(element := (v at:row) at:col) printCR. element == 20 ifTrue:[ exit value:(row @ col) ]. ] ]. nil ] valueWithExit.
result isNil ifTrue:[
'ouch - no 20 found' printCR.
] ifFalse:[
'20 found at ' print. result printCR
]</lang>
- Output:
19 6 1 7 12 20 20 found at 1@6
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>
SPL
<lang spl>'fill array mx,my = 30 > y, 1..my
> x, 1..mx a[x,y] = #.rnd(20)+1 <
< 'scan array > y, 1..my
> x, 1..mx #.output("x=",x,", y=",y, ", a=",a[x,y]) << a[x,y] = 20 < << x!>mx
<</lang>
- Output:
x=1, y=1, a=7 x=2, y=1, a=7 x=3, y=1, a=19 x=4, y=1, a=1 x=5, y=1, a=20
Stata
In Stata macro language, one can only break the innermost loop, with continue, break. There are several ways to cope with this.
First, build the matrix:
<lang stata>matrix a=J(20,20,0) forv i=1/20 { forv j=1/20 { matrix a[`i',`j']=runiformint(1,20) } }</lang>
Use nested forvalues. If 20 is found, set a flag and break the inner loop. In the outer loop, check the flag and break the outer loop if 20 was found.
<lang stata>local q 0 forv i=1/20 { forv j=1/20 { display "check `i',`j'" if el("a",`i',`j')==20 { display "found at `i',`j'" local q 1 continue, break } }
if `q' continue, break } if !`q' { display "not found" }</lang>
Use nested while loops, and check both the loop indices and a flag. One could also use an inner forvalue loop together with an outer while loop.
<lang stata>local q 0 local i=1 while !`q' & `i'<=20 { local j=1 while !`q' & `j'<=20 { display "check `i',`j'" if el("a",`i',`j')==20 { display "found at `i',`j'" local q 1 } local ++j } local ++i } if !`q' { display "not found" }</lang>
Use the exit/capture exception mechanism: exit tos throw an exception, and capture to catch it. Since this catches all exception, you have then to check the value of _rc.
<lang stata>capture { forv i=1/20 { forv j=1/20 { display "check `i',`j'" if el("a",`i',`j')==20 { display "found at `i',`j'" exit -1 } } } } if _rc==-1 { // value was found } else if _rc==0 { display "not found" } else exit _rc</lang>
Mata
In Mata, the situation is simpler: one may return from a program without resort to exceptions, or use the goto statement. It's still possible to use break and flags though.
<lang stata>function findval1(a,x,i0,j0) { n=rows(a) p=cols(a) for (i=1; i<=n; i++) { for (j=1; j<=p; j++) { if (a[i,j]==x) { i0=i j0=j return(1) } } } return(0) }
function findval2(a,x,i0,j0) { n=rows(a) p=cols(a) q=0 for (i=1; i<=n; i++) { for (j=1; j<=p; j++) { if (a[i,j]==x) { i0=i j0=j q=1 goto END } } } END: return(q) }
function findval3(a,x,i0,j0) { n=rows(a) p=cols(a) q=0 for (i=1; i<=n; i++) { for (j=1; j<=p; j++) { if (a[i,j]==x) { i0=i j0=j q=1 break } } if (q) { break } } return(q) }</lang>
Then with any of these functions, the return value indicates whether x has been found in a, and i,j are the indices where it has been found.
<lang stata>a=st_matrix("a") findval1(a,20,i=.,j=.) findval2(a,20,i=.,j=.) findval3(a,20,i=.,j=.)</lang>
Swift
<lang Swift>let array = [[2, 12, 10, 4], [18, 11, 20, 2]]
loop: for row in array {
for element in row { println(" \(element)") if element == 20 { break loop } }
} print("done")</lang>
- Output:
2 12 10 4 18 11 20 done
Tailspin
In Tailspin you break processing by simply not sending a value on in the chain. <lang tailspin> sink find20
def a: $; 1 -> # when <..$a::length> do def i: $; '$#10;' -> !OUT::write 1 -> \( when <$a($i)::length~..> do $i + 1 ! otherwise def j: $; def val: $a($i;$j); ' $val;' -> !OUT::write $val -> \(<~=20> $j + 1 ! \) -> # \) -> #
end find20
[1..10 -> [1..10 -> 20 -> SYS::randomInt -> $ + 1]] -> !find20 </lang>
- Output:
3 4 2 10 10 10 2 16 9 14 10 2 8 7 19 13 9 9 2 6 5 8 11 18 14 5 3 1 7 19 18 18 16 3 1 19 19 8 6 6 18 9 17 16 13 16 12 15 4 2 12 20
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>
- 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-83 BASIC
<lang ti83b>PROGRAM:LOOP (A,B)→dim([C]) For(I,1,A) For(J,1,B) int(rand*20+1)→[C](I,J) End End For(I,1,A) For(J,1,B) Disp [C](I,J) If [C](I,J)=20 Then Stop End End End
3→A:4→B:prgmLOOP</lang>
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
Vala
<lang vala>void main() {
int[,] a = new int[10, 10]; bool broken = false; for (int i = 0; i < 10; i++) for (int j = 0; j < 10; j++) a[i, j] = Random.int_range(0, 21) % 20 + 1;
for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { stdout.printf(" %d", a[i, j]); if (a[i, j] == 20) { broken = true; break; } } stdout.printf("\n"); if (broken) break; }
}</lang>
VBA
<lang VB>Public Sub LoopsNested()
Dim a(1 To 10, 1 To 10) As Integer Randomize For i = 1 To 10 For j = 1 To 10 a(i, j) = Int(20 * Rnd) + 1 Next j Next i For i = 1 To 10 For j = 1 To 10 If a(i, j) <> 20 Then Debug.Print a(i, j), Else i = 10 'Upperbound iterator outerloop Exit For 'Exit For exits only innerloop End If Next j Debug.Print Next i
End Sub</lang>
Visual Basic .NET
VB.NET doesn't have labelled loops, but the Exit statement discriminates between different types of block, allowing for several workarounds other than using a goto.
The set-up code: <lang vbnet>Module Program
Sub Main() Const ROWS = 10 Const COLS = 10
' Initialize with seed 0 to get deterministic output (may vary across .NET versions, though). Dim rand As New Random(0)
' VB uses max index array declarations Dim nums(ROWS - 1, COLS - 1) As Integer
For r = 0 To ROWS - 1 For c = 0 To COLS - 1 nums(r, c) = rand.Next(0, 21) ' Upper bound is exclusive. Next Next
' MISSING IMPLEMENTATION End Sub
End Module</lang>
Implementations:
Perhaps the simplest solution is to use a goto. <lang vbnet> For r = 0 To ROWS - 1
For c = 0 To COLS - 1 Dim val = nums(r, c) Console.WriteLine(val) If val = 20 Then GoTo BREAK Next Next BREAK:</lang>
If, for some reason, a goto is undesirable, an alternative would be to exit a dummy outer block (in this case a single-iteration Do loop). <lang vbnet> Do
For r = 0 To ROWS - 1 For c = 0 To COLS - 1 Dim val = nums(r, c) Console.WriteLine(val) If val = 20 Then Exit Do Next Next Loop While False</lang>
Either For loop can also be converted to a different type of loop. <lang vbnet> For r = 0 To ROWS - 1
Dim c = 0 Do While c <= COLS - 1 Dim val = nums(r, c) Console.WriteLine(val) If val = 20 Then Exit For c += 1 Loop Next</lang>
The search can also be factored out to a separate method <lang vbnet> Sub Find20Impl(arr As Integer(,))
For r = 0 To arr.GetLength(0) - 1 For c = 0 To arr.GetLength(1) - 1 Dim val = arr(r, c) Console.WriteLine(val) If val = 20 Then Exit Sub 'If val = 20 Then Return ' Equivalent to above. Next Next End Sub</lang>
and called from Main(): <lang vbnet> Find20Impl(nums)</lang>
A translation of the VBA above, that sets the iteration variable of the outer For loop to an out-of-range value and exits the inner loop regularly. <lang vbnet> For r = 0 To ROWS - 1
For c = 0 To COLS - 1 Dim val = nums(r, c) Console.WriteLine(val) If val = 20 Then r = ROWS Exit For End If Next Next</lang>
Similarly, a flag variable can be checked by the outer loop. <lang vbnet> Dim done = False
For r = 0 To ROWS - 1 For c = 0 To COLS - 1 Dim val = nums(r, c) Console.WriteLine(val) If val = 20 Then done = True Exit For End If Next If done Then Exit For Next</lang>
- Output:
15 17 16 11 4 11 19 9 20
Vlang
<lang vlang>import rand import rand.seed
fn main() {
rand.seed(seed.time_seed_array(2)) mut values := [][]int{len:10, init: []int{len:10}} for i in 0..values.len{ for j in 0..values[0].len { values[i][j] = rand.intn(20) or {19} +1 } }
outerloop:
for i,row in values { println('${i:3})') for value in row { print(' ${value:3}') if value==20{ break outerloop } } println() }
}</lang>
Wren
Wren doesn't have goto or break label so to break out of nested loops you need to use a flag (found in the code below). <lang ecmascript>import "random" for Random import "/fmt" for Fmt
var rand = Random.new()
var a = List.filled(20, null) for (i in 0..19) {
a[i] = List.filled(20, 0) for (j in 0..19) a[i][j] = rand.int(1, 21)
}
var found = false for (i in 0..19) {
for (j in 0..19) { System.write(Fmt.d(4, a[i][j])) if (a[i][j] == 20) { found = true break } } System.print() if (found) break
}</lang>
- Output:
Sample run:
8 5 4 9 5 7 13 8 8 13 17 10 9 4 8 14 16 5 5 9 11 18 16 9 6 17 14 5 10 13 15 8 2 6 18 20
XBasic
Break out of nested loops by means of an additional variable. <lang xbasic> PROGRAM "loopsnested"
IMPORT "xst" ' for XstGetSystemTime
DECLARE FUNCTION Entry()
' Pseudo-random number generator ' Based on the rand, srand functions from Kernighan & Ritchie's book ' 'The C Programming Language' DECLARE FUNCTION Rand() DECLARE FUNCTION SRand(seed%%)
FUNCTION Entry()
DIM array%[10, 10] XstGetSystemTime (@msec) SRand(INT(msec) MOD 32768) FOR row% = 0 TO 10 FOR col% = 0 TO 10 array%[row%, col%] = INT(Rand() / 32768.0 * 20.0) + 1 NEXT col% NEXT row%
isFound% = $$FALSE FOR row% = 0 TO 10 PRINT "Row:"; row% FOR col% = 0 TO 10 PRINT " Col:"; col%; ", value:"; array%[row%, col%] IF array%[row%, col%] = 20 THEN isFound% = $$TRUE EXIT FOR END IF NEXT col% IFT isFound% THEN EXIT FOR END IF NEXT row%
END FUNCTION
' Return pseudo-random integer on 0..32767 FUNCTION Rand()
#next&& = #next&& * 1103515245 + 12345
END FUNCTION USHORT(#next&& / 65536) MOD 32768
' Set seed for Rand() FUNCTION SRand(seed%%)
#next&& = seed%%
END FUNCTION
END PROGRAM </lang>
- Output:
Row: 0 Col: 0, value: 1 Col: 1, value: 6 Col: 2, value: 15 Col: 3, value: 19 Col: 4, value: 6 Col: 5, value: 7 Col: 6, value: 19 Col: 7, value: 8 Col: 8, value: 11 Col: 9, value: 9 Col: 10, value: 15 Row: 1 Col: 0, value: 3 Col: 1, value: 7 Col: 2, value: 18 Col: 3, value: 1 Col: 4, value: 7 Col: 5, value: 8 Col: 6, value: 9 Col: 7, value: 14 Col: 8, value: 4 Col: 9, value: 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>
zkl
Using nested lists to simulate a 5x5 array. No breakbreak so an exception is used to long jump out of the loop (just 'cause, a state var could also be used). <lang zkl>const N=5; var rows=(0).pump(N,List, (0).pump.fp(N,List,(1).random.fpM("1-",21)) ); try{
foreach r in (N){ foreach c in (N){ x:=rows[r][c]; x.print(","); if (x==20) { println("Found it!"); throw(Exception.Generic); } } } println("Not found");
}catch(Generic){}</lang>
- Output:
14,13,17,11,11,3,15,20,Found it! 3,2,10,14,10,2,2,15,2,13,11,5,12,4,17,8,10,5,14,11,10,14,11,4,1,Not found
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
- 11l
- 360 Assembly
- Action!
- Ada
- ALGOL 60
- ALGOL 68
- AppleScript
- ARM Assembly
- AutoHotkey
- AWK
- BASIC
- Applesoft BASIC
- Commodore BASIC
- Sinclair ZX81 BASIC
- BASIC256
- BBC BASIC
- Bc
- C
- C sharp
- C++
- Chapel
- Clojure
- COBOL
- ColdFusion
- Common Lisp
- D
- Dc
- Delphi
- Pascal
- Dyalect
- E
- EchoLisp
- Elixir
- Erlang
- ERRE
- Euphoria
- F Sharp
- Factor
- Fantom
- Forth
- Fortran
- FreeBASIC
- Frink
- Gambas
- GAP
- Go
- Groovy
- Haskell
- HicEst
- Icon
- Unicon
- J
- Java
- JavaScript
- Jq
- Jsish
- Julia
- Kotlin
- Lambdatalk
- Lasso
- Liberty BASIC
- Lingo
- Lisaac
- LiveCode
- Logo
- Lua
- M2000 Interpreter
- Maple
- Mathematica
- Wolfram Language
- MATLAB
- Octave
- Maxima
- MAXScript
- Microsoft Small Basic
- MOO
- MUMPS
- Neko
- Nemerle
- NetRexx
- NewLISP
- Nim
- NS-HUBASIC
- OCaml
- OoRexx
- Oz
- PARI/GP
- Perl
- Phix
- PHP
- PicoLisp
- Pike
- PL/I
- PureBasic
- Python
- Qi
- Quackery
- R
- Racket
- Raku
- REBOL
- ReScript
- REXX
- Ring
- Ruby
- Run BASIC
- Rust
- Rand
- Sather
- S-BASIC
- Scala
- Scheme
- Scilab
- Seed7
- Sidef
- Smalltalk
- SPL
- Stata
- Swift
- Tailspin
- Tcl
- TI-83 BASIC
- TI-89 BASIC
- TUSCRIPT
- UNIX Shell
- Vala
- VBA
- Visual Basic .NET
- Vlang
- Wren
- Wren-fmt
- XBasic
- XPL0
- Zkl
- ZX Spectrum Basic
- GUISS/Omit