Loops/Nested

From Rosetta Code
Revision as of 17:07, 14 August 2009 by rosettacode>Kevin Reid (→‎TI-89 BASIC: new example)
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.

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

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>

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 

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>

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

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>

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>

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>

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

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.

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