Loops/N plus one half

From Rosetta Code

Jump to: navigation, search
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

Contents

[edit] 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;

[edit] 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:

  FOR i WHILE
print(whole(i, -2));
# WHILE # i < 10 DO
print(", ")
 
OD;
 
print(new line)
FOR i TO 10 DO
print(whole(i, -2));
IF i < 10 THEN
print(", ")
FI
OD;
 
print(new line)
FOR i DO
print(whole(i, -2));
IF i >= 10 THEN GO TO done FI;
print(", ")
 
OD;
done:
print(new line)

Output for all cases above:

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

[edit] AmigaE

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

[edit] 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%

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

[edit] BASIC

Works with: FreeBASIC version 0.20

Works with: RapidQ

DIM i AS INTEGER
 
FOR i=1 TO 10
PRINT i;
IF i=10 THEN EXIT FOR
PRINT ", ";
NEXT i

[edit] Befunge

1+>::.9`#@_" ,",,

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:

"0"                v
1+>::"9"`#v_," ,",,>
>"01",,@

[edit] C

Translation of: C++

#include <stdio.h>
 
int main()
{
int i;
for (i=1; ; i++) {
printf("%d", i);
if (i==10) break;
printf(", ");
}
printf("\n");
return 0;
}

[edit] C++

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

[edit] C#

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

[edit] ColdFusion

With tags:

<cfloop index = "i" from = "1" to = "10">
#i#
<cfif i EQ 10>
<cfbreak />
</cfif>
,
</cfloop>

With script:

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

[edit] Common Lisp

(loop for i from 1 upto 10 do
(princ i)
(if (= i 10) (return))
(princ ", "))

[edit] D

for (int i = 1; ; i++) {
writef(i);
if (i == 10) break;
writef(", ");
}
writefln();

[edit] E

A typical loop+break solution:

var i := 1
while (true) {
print(i)
if (i >= 10) { break }
print(", ")
i += 1
}

Using the loop primitive in a semi-functional style:

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

[edit] Factor

: print-comma-list ( n -- )
[ [1,b] ] keep '[
[ number>string write ]
[ _ = [ ", " write ] unless ] bi
] each nl ;

[edit] FALSE

1[$9>~][$.", "1+]#.

[edit] Forth

: comma-list ( n -- )
dup 1 ?do i 1 .r ." , " loop
. ;
: 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 ;
: comma-list ( n -- )
1
begin dup 1 .r
2dup <>
while ." , " 1+
repeat 2drop ;

[edit] Fortran

Works with: Fortran version 90 and later

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

[edit] Haskell

loop :: IO ()
loop = mapM_ action [1 .. 10]
where action n = do
putStr $ show n
putStr $ if n == 10 then "\n" else ", "

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

[edit] HicEst

DO i = 1, 10
WRITE(APPend) i
IF(i < 10) WRITE(APPend) ", "
ENDDO

[edit] IDL

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

print,indgen(10)+1,format='(10(i,:,","))'

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

for i=1,10 do begin
print,i,format='($,i)'
if i lt 10 then print,",",format='($,a)'
endfor

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

or like this:

for i=1,10 do begin
print,i,format='($,i)'
if i eq 10 then break
print,",",format='($,a)'
end

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

[edit] Icon and Unicon

[edit] Icon

procedure main()
every writes(i := 1 to 10) do
if i = 10 then break write()
else writes(", ")
end

The above can be written more succinctly as:

every writes(c := "",1 to 10) do c := ","
 

[edit] Unicon

The Icon solution works in Unicon.

[edit] 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
)

Example use:

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

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

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

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

   commaAnd=: ":&.> ;@,. -@# {. (<;._1 '/ and /') ,~ (<', ') #~ #  
commaAnd i.5
0, 1, 2, 3 and 4

[edit] 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();
}

[edit] 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));

[edit] 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;
);

[edit] Logo

to comma.list :n
repeat :n-1 [type repcount type "|, |]
print :n
end
 
comma.list 10

[edit] Lua

Translation of C:

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

[edit] 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',`, ')')

[edit] MAXScript

for i in 1 to 10 do
(
format "%" i
if i == 10 then exit
format "%" ", "
)

[edit] 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)

Invoking it

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

[edit] Metafont

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

last := 10;
string s; s := "";
for i = 1 upto last:
s := s & decimal i;
if i <> last: s := s & ", " fi;
endfor
message s;
end

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

[edit] OCaml

let last = 10 in
for i = 1 to last do
print_int i;
if i <> last then
print_string ", ";
done;
print_newline();
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);

[edit] Octave

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

[edit] Oz

Using a for-loop:

 
for N in {List.number 1 10 1} break:Break do
{System.printInfo N}
if N == 10 then {Break} end
{System.printInfo ", "}
end

However, it seems more natural to use a left fold:

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

[edit] 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.

[edit] Perl

foreach my $i (1..10) {
print $i;
last if $i == 10;
print ', ';
}
print "\n";

[edit] Perl 6

Works with: Rakudo version #21 "Seattle"

for 1 .. 10 {
.print;
last if $_ == 10;
print ', ';
}
 
print "\n";

[edit] PHP

for ($i = 1; $i <= 11; $i++) {
echo $i;
if ($i == 10)
break;
echo ', ';
}
echo "\n";

[edit] PicoLisp

(for N 10
(prin N)
(T (= N 10))
(prin ", ") )

[edit] Pike

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

[edit] PL/I

 
do i = 1 to 10;
put edit (trim(i)) (a);
if i < 10 then put edit (', ') (a);
end;
 

[edit] Pop11

lvars i;
for i from 1 to 10 do
printf(i, '%p');
quitif(i = 10);
printf(', ', '%p');
endfor;
printf('\n', '%p');

[edit] PowerShell

Translation of: C

for ($i = 1; $i -le 10; $i++) {
Write-Host -NoNewLine $i
if ($i -eq 10) {
Write-Host
break
}
Write-Host -NoNewLine ", "
}

An interesting alternative solution, although not strictly a loop, even though switch certainly loops over the given range.

switch (1..10) {
{ $true } { Write-Host -NoNewLine $_ }
{ $_ -lt 10 } { Write-Host -NoNewLine ", " }
{ $_ -eq 10 } { Write-Host }
}

[edit] PureBasic

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

[edit] 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:

print ( ', '.join(str(i+1) for i in range(10)) )

But the named pattern is shown by code such as the following:

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

[edit] R

The natural way to solve this task in R is:

paste(1:10, collapse=", ")

The task specifies that we should use a loop however, so this more verbose code is needed.

for(i in 1:10)
{
cat(i)
if(i==10)
{
cat("\n")
break
}
cat(", ")
}

[edit] 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 ""

[edit] REXX

n = 10
i = 1
do forever
call charout , i
i = i + 1
if i > n then
leave
call charout , ', '
end

[edit] Ruby

for i in 1..10 do
print i
break if i == 10
print ", "
end
puts

[edit] Scheme

It is possible to use continuations:

(call-with-current-continuation
(lambda (esc)
(do ((i 1 (+ 1 i))) (#f)
(display i)
(if (= i 10) (esc (newline)))
(display ", "))))

But usually making the tail recursion explicit is enough:

(let loop ((i 0))
(display i)
(if (= i 10)
(newline)
(begin
(display ", ")
(loop (+ 1 i)))))

[edit] 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.

loop    str = str lt(i,10) (i = i + 1) :f(out)
str = str ne(i,10) ',' :s(loop)
out output = str
end

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.

        output('out',1,'-[-r1]')
loop i = lt(i,10) i + 1 :f(end)
out = i
eq(i,10) :s(end)
out = ',' :(loop)
end

Output:

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

[edit] SNUSP

@\>@\>@\>+++++++++<!/+.  >-?\#  digit and loop test
| | \@@@+@+++++# \>>.<.<</ comma and space
| \@@+@@+++++#
\@@@@=++++#

[edit] Tcl

for {set i 1; set end 10} true {incr i} {
puts -nonewline $i
if {$i >= $end} break
puts -nonewline ", "
}
puts ""

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

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

[edit] TI-89 BASIC

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

Local str
"" → str
For i,1,10
str & string(i) → str
If i < 10 Then
str & "," → str
EndIf
EndFor
Disp str

[edit] UnixPipes

The last iteration is handled automatically for us when there is no element in one of the pipes.

yes \ | cat -n | head -n 10 | paste -d\  - <(yes , | head -n 9) | xargs echo

[edit] V

[loop 
[ [10 =] [puts]
[true] [dup put ',' put succ loop]
] when].

Using it

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

[edit] Vedit macro language

This example writes the output into current edit buffer.

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

[edit] Visual Basic .NET

For i = 1 To 10
Console.Write(i)
If i = 10 Then Exit For
Console.Write(", ")
Next
Personal tools
Support