Loops/Nested: Difference between revisions

From Rosetta Code
Content added Content deleted
Line 693: Line 693:
do i = 1 to hbound(x,1);
do i = 1 to hbound(x,1);
do j = 1 to hbound(x,2);
do j = 1 to hbound(x,2);
put (x(i,j));
if x(i,j) = 20 then leave loops;
if x(i,j) = 20 then leave loops;
end;
end;

Revision as of 03:08, 16 August 2010

Task
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 two-dimensional array filled with random number uniformly distributed on [1..20]. The loops iterate rows and columns of the array printing the iterated elements of, until the value 20 is met. Specifically, this task also shows how to break out of nested loops.

Ada

<lang ada>with Ada.Text_IO; use Ada.Text_IO; with Ada.Numerics.Discrete_Random;

procedure Test_Loop_Nested is

  type Value_Type is range 1..20;
  package Random_Values is new Ada.Numerics.Discrete_Random (Value_Type);
  use Random_Values;
  Dice : Generator;
  A : array (1..10, 1..10) of Value_Type :=
         (others => (others => Random (Dice)));

begin

Outer :

  for I in A'Range (1) loop
     for J in A'Range (2) loop
        Put (Value_Type'Image (A (I, J)));
        exit Outer when A (I, J) = 20;
     end loop;
     New_Line;
  end loop Outer;

end Test_Loop_Nested;</lang> Sample output:

 16 3 1 17 13 5 4 2 19 1
 5 5 17 15 17 2 5 5 17 13
 16 10 10 20

ALGOL 68

Translation of: C

- note: This specimen retains the original C coding style.

Works with: ALGOL 68 version Standard - no extensions to language used
Works with: ALGOL 68G version Any - tested with release 1.18.0-9h.tiny
Works with: ELLA ALGOL 68 version Any (with appropriate job cards)

<lang algol68>main: (

   [10][10]INT a; INT i, j;
   FOR i FROM LWB a TO UPB a DO
       FOR j FROM LWB a[i] TO UPB a[i] DO
           a[i][j] := ENTIER (random * 20 + 1)
       OD
   OD ;
   FOR i FROM LWB a TO UPB a DO
       FOR j FROM LWB a[i] TO UPB a[i] DO
           print(whole(a[i][j], -3));
           IF a[i][j] = 20 THEN
               GO TO xkcd com 292 # http://xkcd.com/292/ #
           FI
       OD;
       print(new line)
   OD;

xkcd com 292:

   print(new line)

)</lang> Sample output:

  8 14 17  6 18  1  1  7  9  6
  8  9  1 15  3  1 10 19  6  7
 12 20

AutoHotkey

<lang AutoHotkey>Loop, 10 {

 i := A_Index
 Loop, 10
 {
   j := A_Index
   Random, a%i%%j%, 1, 20
 }

}

Loop, 10 {

 i := A_Index
 Loop, 10
 {
   j := A_Index
   If (a%i%%j% == 20)
     Goto finish
 }

}

finish:

 MsgBox % "a[" . i . "][" . j . "]" is 20

Return</lang>

BASIC

Works with: QuickBasic version 4.5

<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>

C

Using goto (note: gotos are considered harmful): <lang c>#include <stdlib.h>

  1. include <time.h>
  2. include <stdio.h>

int main() {

   int a[10][10], i, j;
   srand(time(NULL));
   for (i = 0; i < 10; i++)
       for (j = 0; j < 10; j++)
           a[i][j] = rand() % 20 + 1;
   for (i = 0; i < 10; i++) {
       for (j = 0; j < 10; j++) {
           printf(" %d", a[i][j]);
           if (a[i][j] == 20)
               goto Done;
       }
       printf("\n");
   }

Done:

   printf("\n");
   return 0;

}</lang>

C#

Uses goto as C# has no way to break from multiple loops

<lang csharp>using System;

class Program {

   static void Main(string[] args) {
       int[,] a = new int[10, 10];
       Random r = new Random();
       for (int i = 0; i < 10; i++) {
           for (int j = 0; j < 10; j++) {
               a[i, j] = r.Next(0, 20) + 1;
           }
       }
       
       for (int i = 0; i < 10; i++) {
           for (int j = 0; j < 10; j++) {
               Console.Write(" {0}", a[i, j]);
               if (a[i, j] == 20) {
                   goto Done;
               }
           }
           Console.WriteLine();
       }
   Done:
       Console.WriteLine();
   }

}</lang>

Clojure

We explicitly return a status flag from the inner loop:

<lang clojure>(ns nested

 (:import (java.util Random)))

(let [generator (Random.)]

 (defn random-int [max]
   "Random integer in [1, max]."
   (inc (.nextInt generator max))))

(defn create-matrix [width height]

 (letfn [(create-row [] (take width (repeatedly #(random-int 20))))]
   (take height (repeatedly create-row))))

(defn print-matrix [matrix]

 (loop [[row & rs] matrix]
   (condp = (loop [[x & xs] row]
              (println x)
              (if (= x 20)
                :stop
                (if xs
                  (recur xs)
                  :continue)))
     :continue (when rs (recur rs))
     :stop     nil)))

(print-matrix (create-matrix 10 10))</lang>

Common Lisp

<lang lisp>(let ((a (make-array '(10 10))))

 (dotimes (i 10)
   (dotimes (j 10)
     (setf (aref a i j) (1+ (random 20)))))
  
 (block outer
   (dotimes (i 10)
     (dotimes (j 10)
       (princ " ")
       (princ (aref a i j))
       (if (= 20 (aref a i j))
           (return-from outer)))
     (terpri))
   (terpri)))</lang>

D

<lang d>import std.stdio, std.random;

void main() {

   int[10][10] m;
   foreach (ref row; m)
       foreach (ref item; row)
           item = rand % 20 + 1;
   outer:
   foreach (row; m)
       foreach (item; row) {
           writef(item, ' ');
           if (item == 20)
               break outer;
       }
   writefln;

}</lang>

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>

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

Works with: Fortran version 90 and later

<lang fortran>program Example

 implicit none
 real :: ra(5,10)
 integer :: ia(5,10)
 integer :: i, j
 call random_number(ra)
 ia = int(ra * 20.0) + 1

outer: do i = 1, size(ia, 1)

        do j = 1, size(ia, 2)
          write(*, "(i3)", advance="no") ia(i,j)
          if (ia(i,j) == 20) exit outer
        end do
        write(*,*)
      end do outer
      

end program Example</lang> Sample output:

 14  2  1 11  8  1 14 11  3 15
  7 15 16  6  7 17  3 20 

Go

<lang go>package main

import (

  "fmt"
  "rand"
  "time"

)

func main() {

 rand.Seed(time.Nanoseconds())
 
 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>

Haskell

<lang haskell>import Data.List

breakIncl p = uncurry ((. take 1). (++)). break p

taskLLB k = map (breakIncl (==k)). breakIncl (k`elem`)</lang> Example: <lang haskell>mij :: Int mij = takeWhile(not.null). unfoldr (Just. splitAt 5) $

     [2, 6, 17, 5, 14, 1, 9, 11, 18, 10, 13, 20, 8, 7, 4, 16, 15, 19, 3, 12]
  • Main> mapM_ (mapM_ print) $ taskLLB 20 mij

2 6 17 5 14 1 9 11 18 10 13 20</lang>

HicEst

<lang hicest>REAL :: n=20, array(n,n)

array = NINT( RAN(10,10) )

DO row = 1, n

 DO col = 1, n
   WRITE(Name) row, col, array(row,col)
   IF( array(row, col) == 20 ) GOTO 99
 ENDDO

ENDDO

99 END</lang>

Icon and Unicon

Icon and Unicon use 'break' to exit loops and execute an expression argument. To exit nested loops 'break' is repeated as the expression.

Icon

<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>

Unicon

The Icon solution works in Unicon.

J

In J, using loops is usually a bad idea.

Here's how the problem statement (ignoring the "requirement" for loops) could be solved, without loops:

<lang J>use=: ({.~ # <. 1+i.&20)@:,</lang>

Here's how the problem could be solved, using loops:

<lang J>doubleLoop=:verb define

 for_row.i.#y do.
   for_col.i.1{$y do.
     smoutput t=.(<row,col) { data
     if.20=t do.return.end.
   end.
 end.

)</lang>

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;
           }
           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>

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>

<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>

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>

OCaml

<lang ocaml># Random.self_init();; - : unit = ()

  1. 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|]|]
  1. for i = 0 to pred 10 do
   for j = 0 to pred 10 do
     m.(i).(j) <- 1 + Random.int 20
   done;
 done;;

- : unit = ()

  1. 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>

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>

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>

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>(catch NIL

  (for Lst (make (do 10 (link (make (do 10 (link (rand 1 20)))))))
     (for N Lst
        (printsp N)
        (and (= N 20) (throw)) ) ) )</lang>


PL/I

<lang PL/I>

  declare x(20,20) fixed;  /* 16 August 2010. */
  x = random()*20 + 1;

loops:

  do i = 1 to hbound(x,1);
     do j = 1 to hbound(x,2);
        put (x(i,j));
        if x(i,j) = 20 then leave loops;
     end;
     if x(i,j) = 20 then leave;
  end;

</lang>

PureBasic

<lang PureBasic>; Creating and filling array Dim Value(10, 5) For a = 0 To 10

 For b = 0 To 5
   Value(a, b) = Random(19) + 1
 Next

Next

iterating trough array

For a = 0 To 10

 For b = 0 To 5
   Debug Value(a, b)
   If Value(a, b) = 20
     ; 2 indicates, that there are two nested lopps to break out
     Break 2
   EndIf
 Next

Next</lang>

Python

Python has only inner loop breaks. Below are two solutions around this problem, the first uses exception handling:

<lang python>import random class Found20(Exception):

   pass

number_array = [[random.randrange(1,21) for x in xrange(10)] for y in xrange(10)]

try:

   for row in number_array:
       for element in row:
           print element,
           if element == 20:
               raise Found20
       print

except Found20:

   print</lang>

The second uses a flag variable:

<lang python>import random

number_array = [[random.randrange(1,21) for x in xrange(10)] for y in xrange(10)] found20 = False

for row in number_array:

   for element in row:
       print element,
       if element == 20:
           found20 = True
           break
   print
   if found20:
       break</lang>

The , after print element suppresses printing a line break. The above has been programmed on Python 2.6; I assume it also works on other Python 2.x versions, but it needs some minor changes in Python 3.

But the normal way to solve this problem in Python is to use a return inside a function: <lang python>from random import randint

def do_scan(m):

   for row in m:
       for item in row:
           print item,
           if item == 20:
               print
               return
   print

m = [[randint(1, 20) for x in xrange(10)] for y in xrange(10)] do_scan(m)</lang>

R

<lang R>m <- 10 n <- 10 mat <- matrix(sample(1:20L, m*n, replace=TRUE), nrow=m); mat done <- FALSE for(i in seq_len(m)) {

  for(j in seq_len(n))
  {
     cat(mat[i,j])
     if(mat[i,j] == 20)
     {
        done <- TRUE
        break
     } 
     cat(", ")     
  }
  if(done) 
  {
     cat("\n")
     break
  }

}</lang>

REBOL

<lang REBOL>REBOL [ Title: "Loop/Nested" Author: oofoe Date: 2010-01-05 URL: http://rosettacode.org/wiki/Loop/Nested ]

Number formatting.

zeropad: func [pad n][

   n: to-string n  insert/dup n "0" (pad - length? n)  n]
Initialize random number generator from current time.

random/seed now

Create array and fill with random numbers, range 1..20.

soup: array [10 10] repeat row soup [forall row [row/1: random 20]]

print "Loop break using state variable:" done: no for y 1 10 1 [ for x 1 10 1 [ prin rejoin [zeropad 2 soup/:x/:y " "] if 20 = soup/:x/:y [done: yes break] ] prin crlf if done [break] ]

print [crlf "Loop break with catch/throw:"] catch [ for y 1 10 1 [ for x 1 10 1 [ prin rejoin [zeropad 2 soup/:x/:y " "] if 20 = soup/:x/:y [throw 'done] ] prin crlf ] ] prin crlf</lang>

Output:

Loop break using state variable:
15 09 11 03 17 07 09 16 03 07
03 15 04 06 13 05 10 06 02 14
17 05 06 12 03 19 03 03 17 04
17 15 14 17 15 07 06 16 13 11
02 08 12 16 04 14 03 19 02 02
02 13 14 14 15 01 10 07 17 03
07 17 20

Loop break with catch/throw:
15 09 11 03 17 07 09 16 03 07
03 15 04 06 13 05 10 06 02 14
17 05 06 12 03 19 03 03 17 04
17 15 14 17 15 07 06 16 13 11
02 08 12 16 04 14 03 19 02 02
02 13 14 14 15 01 10 07 17 03
07 17 20

REXX

Standard REXX has a work around for this: <lang rexx>do i = 1 to 10

   do j = 1 to 10
       numbers.i.j = random(1, 20)
       numbers.i.0 = j
   end
   numbers.0 = i

end

do i = 1 to numbers.0

   do j = 1 to numbers.i.0
       say numbers.i.j
       if numbers.i.j = 20 then
           signal mylabel
   end

end

mylabel:</lang>

Works with: oorexx

:

<lang rexx>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>

Ruby

As the break command only jumps out of the innermost loop, this task requires Ruby's catch/throw functionality. <lang ruby>srand ary = (1..20).to_a.shuffle.each_slice(4).to_a p ary

catch :found_it do

 for row in ary
   for element in row
     print "%2d " % element
     throw :found_it if element == 20
   end
   puts ","
 end

end

puts "done"</lang>

[[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

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>

Scheme

Using call/cc: <lang scheme> (call-with-current-continuation

(lambda (return)
  (for-each (lambda (a)

(for-each (lambda (b) (cond ((= 20 b) (newline) (return)) (else (display " ")(display b)))) a) (newline)) array))) </lang> Using tail-call: <lang scheme> (let loop ((a array))

 (if (pair? a)
     (let loop2 ((b (car a)))

(cond ((null? b) (newline) (loop (cdr a))) ((= 20 (car b)) (newline)) (else (display " ")(display (car b)) (loop2 (cdr b))))))) </lang>

Smalltalk

Works with: GNU Smalltalk

Smalltalk has no ways of escaping from loops (single or nested), even if it is possible to extend its iteration capabilities in several ways. The following code implements a BiArray class with a method that allows iteration over the elements (by columns and then by rows) and execution of a block if a condition is true.

<lang smalltalk>"this simple implementation of a bidimensional array

lacks controls over the indexes, but has a way of iterating
over array's elements, from left to right and top to bottom"

Object subclass: BiArray [

 |cols rows elements|
 BiArray class >> columns: columns  rows: howManyRows [ 
     ^ super basicNew init: columns per: howManyRows
 ]
 init: columns per: howManyRows [
    cols := columns.
    rows := howManyRows.
    elements := Array new: ( columns * howManyRows )
 ]
 calcIndex: biIndex [ "column, row (x,y) to linear"
   ^ ( (biIndex at: 1) + (((biIndex at: 2) - 1) * cols) )
 ]
 at: biIndex [ "biIndex is an indexable containing column row"
    ^ elements at: (self calcIndex: biIndex).
 ]
 directAt: i [ ^ elements at: i ]
 at: biIndex put: anObject [
    elements at: (self calcIndex: biIndex) put: anObject
 ]
 whileTrue: aBlock do: anotherBlock [
    |i lim|
    i := 1. lim := rows * cols.
    [ ( i <= lim )
        & (aBlock value: (self directAt: i) )
    ] whileTrue: [ 
        anotherBlock value: (self directAt: i).
        i := i + 1.
      ]
 ]

].

|biarr| biarr := BiArray columns: 10 rows: 10.

"fill the array; this illustrates nested loop but not how to

escape from them"

1 to: 10 do: [ :c |

 1 to: 10 do: [ :r |
    biarr at: {c . r} put: (Random between: 1 and: 20)
 ]

].

"loop searching for 20; each block gets the element passed as argument" biarr whileTrue: [ :v | v ~= 20 ]

     do: [ :v | v displayNl ]</lang>

Tcl

Tcl only supports single-level breaks; exiting more deeply nested looping requires the use of exceptions, which are considerably more verbose before Tcl 8.6.

Works with: Tcl version 8.6

<lang tcl>set ary [subst [lrepeat 10 [lrepeat 5 {[expr int(rand()*20+1)]}]]]

try {

   foreach row $ary {
       foreach col $row {
           puts -nonewline [format %3s $col]
           if {$col == 20} {
               throw MULTIBREAK "we're done"
           }
       }
       puts ,
   }

} trap MULTIBREAK {} {} puts " done"</lang> Sample output:

 12 13 14 13 15,
  1 14  7 16  3,
 12 11  5  1  9,
 12  5  1  4  2,
  6 11 11  4 11,
  7 14 20 done

TI-89 BASIC

The Stop statement exits the containing program.

<lang ti89b>Prgm

 Local mat,i,j
 © randMat(5, 5) exists but returns -9 to 9 rather than 1 to 20
 newMat(5, 5) → mat
 For i,1,rowDim(mat)
   For j,1,colDim(mat)
     rand(20) → mat[i,j]
   EndFor
 EndFor
 Disp mat
 Pause "Press a key."
 ClrIO
 For i,1,rowDim(mat)
   For j,1,colDim(mat)
     If mat[i,j] = 20 Then
       Stop
     Else
       Output i*8, j*18, mat[i,j]
     EndIf
   EndFor
 EndFor

EndPrgm</lang>