Loops/N plus one half

From Rosetta Code
Revision as of 22:59, 24 November 2010 by Nerketur (talk | contribs) (→‎{{header|E}}: Added code for the Euphoria language,)
Task
Loops/N plus one half
You are encouraged to solve this task according to the task description, using any language you may know.

Quite often one needs loops which, in the last iteration, execute only part of the loop body. The goal of this task is to demonstrate the best way to do this.

Write a loop which writes the comma-separated list

1, 2, 3, 4, 5, 6, 7, 8, 9, 10

using separate output statements for the number and the comma from within the body of the loop.

See also: Loop/Break

Ada

<lang ada>with Ada.Text_Io; use Ada.Text_Io; with Ada.Integer_Text_Io; use Ada.Integer_Text_Io;

procedure Loop_And_Half is

  I : Positive := 1;

begin

  loop
     Put(Item => I, Width => 1);
     exit when I = 10;
     Put(", ");
     I := I + 1;
  end loop;
  New_Line;

end Loop_And_Half;</lang>

ALGOL 68

Works with: ALGOL 68 version Standard - no extensions to language used
Works with: ALGOL 68G version Any - tested with release mk15-0.8b.fc9.i386
Works with: ELLA ALGOL 68 version Any (with appropriate job cards) - tested with release 1.8.8d.fc9.i386

There are three common ways of achieving n+½ loops:

<lang algol68> FOR i WHILE
   print(whole(i, -2));
  1. WHILE # i < 10 DO
   print(", ")
 OD;
 print(new line)</lang>
<lang algol68>FOR i TO 10 DO
 print(whole(i, -2));
 IF i < 10 THEN
   print(", ")
 FI

OD;

print(new line)</lang>

<lang algol68>FOR i DO
 print(whole(i, -2));
 IF i >= 10 THEN GO TO done FI;
 print(", ")

OD; done: print(new line)</lang>

Output for all cases above:

 1,  2,  3,  4,  5,  6,  7,  8,  9, 10

AmigaE

<lang amigae>PROC main()

 DEF i
 FOR i := 1 TO 10
   WriteF('\d', i)
   EXIT i = 10
   WriteF(', ')
 ENDFOR

ENDPROC</lang>

AutoHotkey

<lang AutoHotkey>Loop, 9  ; loop 9 times {

 output .= A_Index    ; append the index of the current loop to the output var
 If (A_Index <> 9)    ; if it isn't the 9th iteration of the loop
   output .= ", "     ; append ", " to the output var

} MsgBox, %output%</lang>

AWK

<lang awk>$ awk 'BEGIN{for(i=1;i<=10;i++){printf i;if(i<10)printf ", "};print}' 1, 2, 3, 4, 5, 6, 7, 8, 9, 10</lang>

Bash

<lang bash>for ((i=1;i<=$((last=10));i++)); do

 echo -n $i
 [ $i -eq $last ] && break
 echo -n ", "

done</lang>

BASIC

Works with: FreeBASIC version 0.20
Works with: RapidQ

<lang qbasic>DIM i AS Integer

FOR i=1 TO 10

   PRINT i;
   IF i=10 THEN EXIT FOR
   PRINT ", ";

NEXT i</lang>

Befunge

<lang befunge>1+>::.9`#@_" ,",,</lang> This code is a good answer. However, most Befunge implementations print a " " after using . (output number), so this program prints "1 , 2 , 3 ..." with unnecessary extra spaces. A bypass for this is possible, yet slightly less sane: <lang befunge>"0" v 1+>::"9"`#v_," ,",,>

         >"01",,@</lang>

C

Translation of: C++

<lang c>#include <stdio.h>

int main() {

 int i;
 for (i=1; ; i++) {
   printf("%d", i);
   if (i==10) break;
   printf(", ");
 }
 printf("\n");
 return 0;

}</lang>

C++

<lang cpp>#include <iostream>

int main() {

 for (int i = 1; ; i++)
 {
   std::cout << i;
   if (i == 10)
     break;
   std::cout << ", ";
 }
 std::cout << std::endl;
 return 0;

}</lang>

C#

<lang csharp>using System;

class Program {

   static void Main(string[] args)
   {
       for (int i = 1; ; i++)
       {
           Console.Write(i);
           if (i == 10) break;
           Console.Write(", ");
       }
       Console.WriteLine();
   }

}</lang>

ColdFusion

With tags: <lang cfm><cfloop index = "i" from = "1" to = "10">

 #i#
 <cfif i EQ 10>
   <cfbreak />
 </cfif>
 , 

</cfloop></lang>

With script: <lang cfm><cfscript>

 for( i = 1; i <= 10; i++ ) //note: the ++ notation works only on version 8 up, otherwise use i=i+1
 {
   writeOutput( i );
   
   if( i == 10 )
   {
     break;
   }
   writeOutput( ", " );
 }

</cfscript></lang>

Common Lisp

<lang lisp>(loop for i from 1 upto 10 do

 (princ i)
 (if (= i 10) (return))
 (princ ", "))</lang>

D

<lang d>for (int i = 1; ; i++) {

 writef(i);
 if (i == 10) break;
 writef(", ");

} writefln();</lang>

E

A typical loop+break solution: <lang e>var i := 1 while (true) {

   print(i)
   if (i >= 10) { break }
   print(", ")
   i += 1

}</lang>

Using the loop primitive in a semi-functional style:

<lang e>var i := 1 __loop(fn {

   print(i)
   if (i >= 10) {
       false
   } else {
       print(", ")
       i += 1
       true 
   }

})</lang>

Euphoria

<lang Euphoria> for i = 1 to 10 do

   printf(1, "%g", {i})
   if i < 10 then
       puts(1, ", ")
   end if

end for </lang>

While, yes, use of exit would also work here, it is slightly faster to code it this way, if only the last iteration has something different.

Factor

<lang factor>: print-comma-list ( n -- )

   [ [1,b] ] keep '[
       [ number>string write ]
       [ _ = [ ", " write ] unless ] bi
   ] each nl ;</lang>

FALSE

<lang false>1[$9>~][$.", "1+]#.</lang>

Forth

<lang forth>: comma-list ( n -- )

 dup 1 ?do  i 1 .r ." , " loop
 . ;</lang>

<lang forth>: comma-list ( n -- )

 dup 1+ 1 do
   i 1 .r
   dup i = if leave then   \ or DROP UNLOOP EXIT to exit loop and the function
   [char] , emit space
 loop drop ;</lang>

<lang forth>: comma-list ( n -- )

 1
 begin  dup 1 .r
        2dup <>
 while  ." , " 1+
 repeat 2drop ;</lang>

Fortran

Works with: Fortran version 90 and later

<lang fortran>i = 1 do

 write(*, '(I0)', advance='no') i
 if ( i == 10 ) exit
 write(*, '(A)', advance='no') ', '
 i = i + 1

end do write(*,*)</lang>

Haskell

<lang haskell>loop :: IO () loop = mapM_ action [1 .. 10]

 where action n = do
           putStr $ show n
           putStr $ if n == 10 then "\n" else ", "</lang>

It is, however, arguable whether mapM_ counts as a loop.

HicEst

<lang hicest>DO i = 1, 10

   WRITE(APPend) i
   IF(i < 10) WRITE(APPend) ", "

ENDDO</lang>

IDL

Nobody would ever use a loop in IDL to output a vector of numbers - the requisite output would be generated something like this:

<lang idl>print,indgen(10)+1,format='(10(i,:,","))'</lang>

However if a loop had to be used it could be done like this:

<lang idl>for i=1,10 do begin

print,i,format='($,i)'
if i lt 10 then print,",",format='($,a)'

endfor</lang>

(which merely suppresses the printing of the comma in the last iteration);

or like this:

<lang idl>for i=1,10 do begin

print,i,format='($,i)'
if i eq 10 then break
print,",",format='($,a)'

end</lang>

(which terminates the loop early if the last element is reached).

Icon and Unicon

Icon

<lang Icon>procedure main() every writes(i := 1 to 10) do

  if i = 10 then break write()
  else writes(", ")

end</lang>

The above can be written more succinctly as: <lang Icon>every writes(c := "",1 to 10) do c := "," </lang>

Unicon

The Icon solution works in Unicon.

J

<lang j>output=: verb define

 buffer=: buffer,y

)

loopy=: verb define

 buffer=: 
 for_n. 1+i.10 do.
   output ":n
   if. n<10 do.
     output ', '
   end.
 end.
 smoutput buffer

)</lang>

Example use: <lang j> loopy 0 1, 2, 3, 4, 5, 6, 7, 8, 9, 10</lang>

That said, note that neither loops nor output statements are necessary:

<lang j>  ;}.,(', ' ; ":)&> 1+i.10 1, 2, 3, 4, 5, 6, 7, 8, 9, 10</lang>

And, note also that this sort of data driven approach can also deal with more complex issues:

<lang j> commaAnd=: ":&.> ;@,. -@# {. (<;._1 '/ and /') ,~ (<', ') #~ #

  commaAnd i.5

0, 1, 2, 3 and 4</lang>

Java

<lang java>public static void main(String[] args) {

   for (int i = 1; ; i++) {
       System.out.print(i);
       if (i == 10)
           break;
       System.out.print(", ");
   }
   System.out.println();

}</lang>

JavaScript

<lang javascript>function loop_plus_half(iterStart, iterTerm) {

 var returnString = "";
 for (int i = iterStart; ; i++)
 {
   returnString += i + ;
   if (i == iterTerm)
     break;
   returnString += ", ";
 }
 return returnString;

}

alert(loop_plus_half(1,10));</lang>

Lisaac

<lang Lisaac>Section Header

+ name := LOOP_AND_HALF;

Section Public

- main <- (

 + i : INTEGER;
 i := 1;
 {
   i.print;
   i = 10
 }.until_do {
   ", ".print;
   i := i + 1;
 };
 '\n'.print;

);</lang>

<lang logo>to comma.list :n

 repeat :n-1 [type repcount type "|, |]
 print :n

end

comma.list 10</lang>

Lua

Translation of C: <lang lua>for i = 1, 10 do

 io.write(i)
 if i == 10 then break end
 io.write", "

end</lang>

M4

<lang M4>define(`break',

  `define(`ulim',llim)')

define(`for',

  `ifelse($#,0,``$0,
  `define(`ulim',$3)`'define(`llim',$2)`'ifelse(ifelse($3,`',1,
        `eval($2<=$3)'),1,
  `pushdef(`$1',$2)$4`'popdef(`$1')$0(`$1',incr($2),ulim,`$4')')')')

for(`x',`1',`',

  `x`'ifelse(x,10,`break',`, ')')</lang>

Mathematica

<lang Mathematica>i = 1; s = ""; While[True,

s = s <> ToString@i;
If[i == 10, Break[]];
s = s <> ",";
i++;
]

s</lang>

MAXScript

<lang maxscript>for i in 1 to 10 do (

   format "%" i
   if i == 10 then exit
   format "%" ", "

)</lang>

Make

<lang make>NEXT=`expr $* + 1` MAX=10 RES=1

all: 1-n;

$(MAX)-n:

      @echo $(RES)

%-n:

      @-make -f loop.mk $(NEXT)-n MAX=$(MAX) RES=$(RES),$(NEXT)</lang>

Invoking it

|make -f loop.mk MAX=10
1,2,3,4,5,6,7,8,9,10

Metafont

Since message append always a newline, we need building the output inside a string, and then we output it.

<lang metafont>last := 10; string s; s := ""; for i = 1 upto last:

 s := s & decimal i;
 if i <> last: s := s & ", " fi;

endfor message s; end</lang>

MUMPS

<lang MUMPS>LOOPHALF

NEW I
FOR I=1:1:10 DO
.WRITE I
.IF I'=10 WRITE ", "
QUIT
;Alternate
NEW I FOR I=1:1:10 WRITE I WRITE:I'=10 ", "
KILL I QUIT</lang>

Output:

USER>D LOOPHALF^ROSETTA
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
USER>D LOOPHALF+7^ROSETTA
1, 2, 3, 4, 5, 6, 7, 8, 9, 10

Objeck

<lang objeck> bundle Default {

 class Hello {
   function : Main(args : String[]) ~ Nil {
     for(i := 1; true; i += 1;) {
       i->Print();
       if(i = 10) {
         break;
       };
       ", "->Print();
     };
     '\n'->Print();
   }
 }

} </lang>

OCaml

<lang ocaml>let last = 10 in for i = 1 to last do

 print_int i;
 if i <> last then
   print_string ", ";

done; print_newline();</lang>

<lang ocaml>let ints = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] in let str_ints = List.map string_of_int ints in print_endline (String.concat ", " str_ints);</lang>

Octave

<lang octave>i = 1; s = ""; while(1)

 s = sprintf("%s%d", s, i);
 if ( i == 10 )
   break;
 endif
 s = strcat(s, ", ");
 i++;

endwhile disp(s)</lang>

Oz

Using a for-loop: <lang oz> for N in {List.number 1 10 1} break:Break do

  {System.printInfo N}
  if N == 10 then {Break} end
  {System.printInfo ", "}

end</lang>

However, it seems more natural to use a left fold: <lang oz>declare

 fun {CommaSep Xs}
    case Xs of nil then nil
    [] X|Xr then

{FoldL Xr fun {$ Z X} Z#", "#X end X}

    end
 end

in

 {System.showInfo {CommaSep {List.number 1 10 1}}}</lang>

Pascal

<lang pascal>program numlist(output);

var

 i: integer;

begin

 for i := 1 to 10 do
   begin
     write(i);
     if i <> 10 then
       write(', ')
   end;
 writeln;

end.</lang>

Perl

<lang perl>foreach my $i (1..10) {

   print $i;
   last if $i == 10;
   print ', ';

} print "\n";</lang>

Perl 6

Works with: Rakudo version #21 "Seattle"

<lang perl6>for 1 .. 10 {

   .print;
   last if $_ == 10;
   print ', ';

}

print "\n";</lang>

PHP

<lang php>for ($i = 1; $i <= 11; $i++) {

   echo $i;
   if ($i == 10)
       break;
   echo ', ';

} echo "\n";</lang>

PicoLisp

<lang PicoLisp>(for N 10

  (prin N)
  (T (= N 10))
  (prin ", ") )</lang>

Pike

<lang pike> int main(){

  for(int i = 1; i <= 11; i++){
     write(sprintf("%d",i));
     if(i == 10){
        break;
     }
     write(", ");
  }
  write("\n");

}</lang>

PL/I

<lang PL/I> do i = 1 to 10;

  put edit (trim(i)) (a);
  if i < 10 then put edit (', ') (a);

end; </lang>

Pop11

<lang pop11>lvars i; for i from 1 to 10 do

   printf(i, '%p');
   quitif(i = 10);
   printf(', ', '%p');

endfor; printf('\n', '%p');</lang>

PowerShell

Translation of: C

<lang powershell>for ($i = 1; $i -le 10; $i++) {

   Write-Host -NoNewLine $i
   if ($i -eq 10) {
       Write-Host
       break
   }
   Write-Host -NoNewLine ", "

}</lang> An interesting alternative solution, although not strictly a loop, even though switch certainly loops over the given range. <lang powershell>switch (1..10) {

   { $true }     { Write-Host -NoNewLine $_ }
   { $_ -lt 10 } { Write-Host -NoNewLine ", " }
   { $_ -eq 10 } { Write-Host }

}</lang>

PureBasic

<lang PureBasic>x=1 Repeat

 Print(Str(x))
 x+1
 If x>10: Break: EndIf
 Print(", ")

ForEver</lang>

Python

The particular pattern and example chosen in the task description is recognised by the Python language and their are more idiomatic ways to achieve the result that don't even require an explicit conditional test such as: <lang python>print ( ', '.join(str(i+1) for i in range(10)) )</lang> But the named pattern is shown by code such as the following: <lang python>>>> from sys import stdout >>> write = stdout.write >>> n, i = 10, 1 >>> while True:

   write(i)
   i += 1
   if i > n:
       break
   write(', ')


1, 2, 3, 4, 5, 6, 7, 8, 9, 10 >>></lang>

R

The natural way to solve this task in R is: <lang R>paste(1:10, collapse=", ")</lang> The task specifies that we should use a loop however, so this more verbose code is needed. <lang R>for(i in 1:10) {

  cat(i)
  if(i==10) 
  {
     cat("\n")
     break
  }
  cat(", ")

}</lang>

REBOL

<lang REBOL>REBOL [

   Title: "Loop Plus Half"
   Date: 2009-12-16
   Author: oofoe
   URL: http://rosettacode.org/wiki/Loop/n_plus_one_half

]

repeat i 10 [ prin i if 10 = i [break] prin ", " ] print ""</lang>

REXX

<lang rexx>n = 10 i = 1 do forever

   call charout , i
   i = i + 1
   if i > n then
       leave
   call charout , ', '

end</lang>

Ruby

<lang ruby>for i in 1..10 do

  print i
  break if i == 10
  print ", "

end puts</lang>

Scheme

It is possible to use continuations: <lang scheme>(call-with-current-continuation

(lambda (esc)
  (do ((i 1 (+ 1 i))) (#f)
    (display i)
    (if (= i 10) (esc (newline)))
    (display ", "))))</lang>

But usually making the tail recursion explicit is enough: <lang scheme>(let loop ((i 0))

 (display i)
 (if (= i 10)
     (newline)
     (begin
       (display ", ")
       (loop (+ 1 i)))))</lang>

SNOBOL4

It's idiomatic in Snobol to accumulate the result in a string buffer for line output, and to use the same statement for loop control and the comma.

<lang SNOBOL4>loop str = str lt(i,10) (i = i + 1) :f(out)

       str = str ne(i,10) ',' :s(loop)

out output = str end</lang>

Works with: Macro Spitbol

For the task description, it's possible (implementation dependent) to set an output variable to raw mode for character output within the loop. This example also breaks the loop explicitly.

<lang SNOBOL4> output('out',1,'-[-r1]') loop i = lt(i,10) i + 1 :f(end)

       out = i
       eq(i,10) :s(end)
       out = ',' :(loop)

end</lang>

Output:

1,2,3,4,5,6,7,8,9,10

SNUSP

<lang snusp>@\>@\>@\>+++++++++<!/+. >-?\# digit and loop test

|  |  \@@@+@+++++# \>>.<.<</    comma and space
|  \@@+@@+++++#      
\@@@@=++++#</lang>

Tcl

<lang tcl>for {set i 1; set end 10} true {incr i} {

   puts -nonewline $i
   if {$i >= $end} break
   puts -nonewline ", "

} puts ""</lang> However, that's not how the specific task (printing 1..10 with comma separators) would normally be done. (Note, the solution below is not a solution to the half-looping problem.) <lang tcl>proc range {from to} {

   set result {}
   for {set i $from} {$i <= $to} {incr i} {
       lappend result $i
   }
   return $i

}

puts [join [range 1 10] ", "] ;# ==> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10</lang>

TI-89 BASIC

There is no horizontal cursor position on the program IO screen, so we concatenate strings instead.

<lang ti89b>Local str "" → str For i,1,10

 str & string(i) → str
 If i < 10 Then
   str & "," → str
 EndIf

EndFor Disp str</lang>

UnixPipes

The last iteration is handled automatically for us when there is no element in one of the pipes. <lang bash>yes \ | cat -n | head -n 10 | paste -d\ - <(yes , | head -n 9) | xargs echo</lang>

UNIX Shell

<lang bash>for(( Z=1; Z<=10; Z++ )); do

   echo -e "$Z\c"
   if (( Z != 10 )); then
       echo -e ", \c"
   fi

done</lang>

V

<lang v>[loop

  [ [10 =] [puts]
    [true] [dup put ',' put succ loop]
  ] when].</lang>

Using it

|1 loop
=1,2,3,4,5,6,7,8,9,10

Vedit macro language

This example writes the output into current edit buffer. <lang vedit>for (#1 = 1; 1; #1++) {

   Num_Ins(#1, LEFT+NOCR)
   if (#1 == 10) { Break }
   Ins_Text(", ")

} Ins_Newline</lang>

Visual Basic .NET

<lang vbnet>For i = 1 To 10

   Console.Write(i)
   If i = 10 Then Exit For
   Console.Write(", ")

Next</lang>