Loops/Nested: Difference between revisions
(Added Oz example.) |
(→{{header|R}}: Added REBOL example.) |
||
Line 591: | Line 591: | ||
} |
} |
||
}</lang> |
}</lang> |
||
=={{header|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 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: |
|||
<pre>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</pre> |
|||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
Revision as of 07:59, 5 January 2010
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
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
<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>
- include <time.h>
- include <stdio.h>
int main() {
int a[10][10], i, j;
srand(time(NULL)); for (i = 0; i < 10; i++) for (j = 0; j < 10; j++) a[i][j] = rand() % 20 + 1;
for (i = 0; i < 10; i++) { for (j = 0; j < 10; j++) { printf(" %d", a[i][j]); if (a[i][j] == 20) goto Done; } printf("\n"); }
Done:
printf("\n"); return 0;
}</lang>
C#
Uses goto as C# has no way to break from multiple loops
<lang csharp>using System;
class Program {
static void Main(string[] args) { int[,] a = new int[10, 10]; Random r = new Random();
for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { a[i, j] = r.Next(0, 20) + 1; } } for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { Console.Write(" {0}", a[i, j]); if (a[i, j] == 20) { goto Done; } } Console.WriteLine(); } Done: Console.WriteLine(); }
}</lang>
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
<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
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>
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>
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>
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 = ()
- 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>
Oz
<lang oz>declare
Height = 10 Width = 10 Matrix = {List.make Height}
in
%% fill nested list for Row in Matrix do Row = {List.make Width} for X in Row do X = {OS.rand} mod 20 +1 end end
%% 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</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>
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 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
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
Smalltalk
Smalltalk has no ways of escaping from loops (single or nested), even if it is possible to extend its iteration capabilities in several ways. The following code implements a BiArray class with a method that allows iteration over the elements (by columns and then by rows) and execution of a block if a condition is true.
<lang smalltalk>"this simple implementation of a bidimensional array
lacks controls over the indexes, but has a way of iterating over array's elements, from left to right and top to bottom"
Object subclass: BiArray [
|cols rows elements| BiArray class >> columns: columns rows: howManyRows [ ^ super basicNew init: columns per: howManyRows ] init: columns per: howManyRows [ cols := columns. rows := howManyRows. elements := Array new: ( columns * howManyRows ) ] calcIndex: biIndex [ "column, row (x,y) to linear" ^ ( (biIndex at: 1) + (((biIndex at: 2) - 1) * cols) ) ] at: biIndex [ "biIndex is an indexable containing column row" ^ elements at: (self calcIndex: biIndex). ] directAt: i [ ^ elements at: i ] at: biIndex put: anObject [ elements at: (self calcIndex: biIndex) put: anObject ] whileTrue: aBlock do: anotherBlock [ |i lim| i := 1. lim := rows * cols. [ ( i <= lim ) & (aBlock value: (self directAt: i) ) ] whileTrue: [ anotherBlock value: (self directAt: i). i := i + 1. ] ]
].
|biarr| biarr := BiArray columns: 10 rows: 10.
"fill the array; this illustrates nested loop but not how to
escape from them"
1 to: 10 do: [ :c |
1 to: 10 do: [ :r | biarr at: {c . r} put: (Random between: 1 and: 20) ]
].
"loop searching for 20; each block gets the element passed as argument" biarr whileTrue: [ :v | v ~= 20 ]
do: [ :v | v displayNl ]</lang>
Tcl
Tcl only supports single-level breaks; exiting more deeply nested looping requires the use of exceptions, which are considerably more verbose before Tcl 8.6.
<lang tcl>set ary [subst [lrepeat 10 [lrepeat 5 {[expr int(rand()*20+1)]}]]]
try {
foreach row $ary { foreach col $row { puts -nonewline [format %3s $col] if {$col == 20} { throw MULTIBREAK "we're done" } } puts , }
} trap MULTIBREAK {} {} puts " done"</lang> Sample output:
12 13 14 13 15, 1 14 7 16 3, 12 11 5 1 9, 12 5 1 4 2, 6 11 11 4 11, 7 14 20 done
TI-89 BASIC
The Stop statement exits the containing program.
<lang ti89b>Prgm
Local mat,i,j © randMat(5, 5) exists but returns -9 to 9 rather than 1 to 20 newMat(5, 5) → mat For i,1,rowDim(mat) For j,1,colDim(mat) rand(20) → mat[i,j] EndFor EndFor Disp mat Pause "Press a key." ClrIO For i,1,rowDim(mat) For j,1,colDim(mat) If mat[i,j] = 20 Then Stop Else Output i*8, j*18, mat[i,j] EndIf EndFor EndFor
EndPrgm</lang>