40
\$\begingroup\$

Your very own "for" instruction

Assuming you have the following input : a, b, c, d

Input can be in one-line using any format "a/b/c/d" or "a,b,c,d" etc..

You can also have 4 inputs.

You must code the following behaviour (pseudo-code here) :

var i = <a>
while (i <b> <c>)
    print i
    i = i + <d>
    print "\n"

Here are some tests cases :

input : 1,<,10,1
output :
1
2
3
4
5
6
7
8
9

One more :

input : 20,>,10,1
output :
20
21
22
23
24
25
26
27
...
infinite loop / program crashes
  • a is an integer, the initial value of i.

  • b is a string or a char, it can't be something else, the comparator used in the ending condition of the for loop.

    b can and must be one of the following strings :

    - ">"
    - "<"
    
  • c is an integer, the number used in the ending condition of the for loop.

  • d is an integer that is added to i at every loop.

This is code-golf, the shortest answer wins !

\$\endgroup\$
4
  • 1
    \$\begingroup\$ Can the numbers be returned from a function as a list/sequence, rather than printed to stdout? \$\endgroup\$
    – smls
    Jan 26, 2017 at 17:07
  • \$\begingroup\$ @smls Nope sorry, the output must be like the examples ! \$\endgroup\$
    – Sygmei
    Jan 26, 2017 at 20:37
  • 1
    \$\begingroup\$ It says my code should follow the pseudo-code and there's a print "\n", but I am using javascript's alert for each line. Would that be acceptable, or would I have to use console.log instead making my answer longer? \$\endgroup\$
    – user64039
    Jan 27, 2017 at 10:46
  • 2
    \$\begingroup\$ You can use the alert function as a way to ouput but you can't use multiple alerts. Something like alert("23\n24\n25"); would work whereas alert("23"); alert("24"); alert(25); wouldn't \$\endgroup\$
    – Sygmei
    Jan 27, 2017 at 10:56

39 Answers 39

1
2
2
\$\begingroup\$

tcl, 52

proc F {a b c d} {while \$a$b$c {puts $a;incr a $d}}

demo

\$\endgroup\$
2
  • \$\begingroup\$ How is this using d to decide by how much to increment a? \$\endgroup\$ Jan 28, 2017 at 13:03
  • \$\begingroup\$ @PaŭloEbermann: My mistake! UPDATED! \$\endgroup\$
    – sergiol
    Jan 28, 2017 at 13:05
2
\$\begingroup\$

dc, 47 bytes

dc, 48 bytes

Also Bash + Unix utilities, 29 bytes

dc (47 bytes):

1sb[_1sb]s zz?sdlb*sc[pld+lnx]sl[dlb*lcr<l]dsnx

Try it online!

Note that negative numbers must be entered with an underscore instead of a minus sign, because that's how dc accepts numeric input. So write, for example, _5 instead of -5.


dc can't read character or string input into a variable and process it (there's a more detailed explanation below), but I found two ways of working around this:

The 47-byte dc solution works on input that has argument1 and argument2 reversed, with spaces as the delimiter. So counting from 1 up to (but not including) 10 in steps of 3 would be entered as:

< 1 10 3

If it's not acceptable to change the order of the arguments, I also give a 48-byte dc solution which keeps the original order of the arguments. This one uses zz as the delimiter between arguments. So counting from 1 up to (but not including) 10 in steps of 3 again would use the following input line:

1zz<zz10zz3

Finally, the same ideas yield a 29-byte bash solution.


Details on dc's lack of string processing, and how this program deals with that:

Handling this problem in dc is tricky, because dc doesn't accept string or char input as most languages do. When dc reads an input string, it immediately runs that string as a dc program (a macro), and then discards the string. You can't store the characters of the string in memory and process them later, or in any other way. This interferes with the requirement to have '<' or '>' in the input.

I'll show two ways around this. In the solution above (47 bytes), we switch the order of the first two inputs. The input delimiter is the space character. For example, to count from 1 up to (but not including) 10 in steps of 3, you'd input

< 1 10 3

Here's the idea behind this solution:

Macros in dc are stored in registers, and registers have single-character names. I store a macro in the register whose name is just a space character.

The program works by pushing a 0 and 1 on the stack before getting the input. Then, when the input is run as a dc program (which is what dc does with input lines), the '<' or '>' character is executed as a command, which is a conditional macro execution of the macro whose name is the next char after the '<' or '>'. Specifically, the top two items on the stack are popped. If the first item popped is < (respectively, >) the second item popped, the indicated macro is executed. The next character (after the '<' or '>') is a space, so the macro that we've stored in the register whose name is the space char is the one executed if the condition holds. But we had pushed 0 and 1 on the stack, so the first item popped was a 1, and the second item popped was a 0. As a result, the macro is executed only if the conditional test was >, not <. This lets us distinguish between '<' and '>' in the input.

The remaining items in the line are just numbers, and dc will simply push those numbers, in turn, on the stack.

Here's a detailed description. Most of the time, the counting variable (i in the pseudocode in the problem statement) is stored at the top of the stack.

1sb             Store 1 in register b.  (b will end up being 1 for '<', and -1 for '>').
[_1sb]s         Note that there is a space after the second s.  So the space char is the name of a macro which stores -1 in b.
z               Push 0 on the stack.
z               Push 1 on the stack.
?               Accept input in the format above.  This will:
                    - Store 1 or -1 in b, depending on whether you've typed "<" or ">"
                    - Push each of the three numbers in turn on the stack.
sd              Save the increment in register d.
lb*sc           Save either limit or -limit in register c, depending on whether the input started with "<" or ">".
[pld+lnx]sl     Define a macro called l which is the body of our loop:
                    - Prints the top of the stack
                    - Adds the increment to the top of the stack.
                    - Calls macro n (the loop test).

 [dlb*lcr<l]dsn  Define a macro called n which is the test of the loop:
                    It checks to see if i (at the top of the stack) times b is less than c; if so, it calls macro l (looping back).
 x               Execute the loop test macro initially (a while loop needs to have a test at the top before entering the loop the first time).

On the other hand, the OP stated:

Input can be in one-line using any format "a/b/c/d" or "a,b,c,d" etc.

So maybe it isn't legitimate to switch the order and require b before a in the input.

Here's an alternative which keeps a, b, c, and d in their original order. We are allowed to use any delimiter; I'll use zz as the delimiter. So counting from 1 up to (but not including) 10 in steps of 3 would be entered as:

1zz<zz10zz3

The new program, with zz-delimited input, is

dc (48 bytes):

1sb[_1sb]sz?sdiilb*sci[pld+lnx]sl[dlb*lcr<l]dsnx

This is one byte longer than the 47-byte first solution.

Try the zz-delimited version online!

I personally think the different-order < 1 10 3 formatting is more in the spirit of the problem, but maybe 1zz<zz10zz3 better meets the actual technical specification.

You could probably get a shorter solution if you allowed different delimiters between the different input arguments, but I don't think that's in the spirit of the problem.

Bash + Unix utilities, 29 bytes

You can turn the underlying idea above into a bash program (which calls dc); this avoids all the difficulties with "<" and ">", and it also simplifies handling the various numeric parameters, so it's only 29 bytes long, the same as @zeppelin's bash+bc answer.

bash version (29 bytes):

dc -e[p$4+d$3r$2l]sl$1d$3r$2l

Try the bash version online!

Here's a description of how the dc program inside the bash program works:

The value of i is stored at the top of the stack most of the time.

[      Start of macro (i is at the top of the stack). This macro will be called l.
p      Print i
$4+    i += (4th argument)
d      Duplicate i at the top of the stack.
$3     Push the 3rd argument onto the stack.
r      Swap the top two items on the stack, so i is at the top and arg3 is second
$2l    $2 is "<" or ">", causing the top two items to be popped from the stack, and macro l is then called (effectively looping back) if i < arg3 or i > arg3, respectively.
]sl    End of macro definition; store macro in register l.

$1     Push argument 1 onto the stack (i = 1st argument).
d$3r$2l Just as above, call macro l if i < arg3, or i > arg3, depending on whether arg2 is "<" or ">"
\$\endgroup\$
1
\$\begingroup\$

Pari/GP , 48 Bytes

f(a,b,c,d)=while(eval(Str(a,b,c)),print(a);a+=d)

Testing

f(4,"<",7,1)  \\ input
4             \\ output
5
6
\$\endgroup\$
1
\$\begingroup\$

C#, 77 bytes

(a,b,c,d)=>{for(int i=a;b==">"?i<c:i>c;i+=d){System.Console.Write(i+"\n");}};
\$\endgroup\$
1
\$\begingroup\$

F#, 71 106 97 bytes

fun a b c d->let i=ref a in while(b !i c)do printfn"%i%s"!i d;i:=!i+1;done

I didn't read the question fully!

fun a b c d->let i=ref a in while((if b='<'then(<)else(>))!i c)do printfn"%i%s"!i d;i:=!i+1;done
\$\endgroup\$
1
\$\begingroup\$

Ruby, 37 bytes

->a,b,c,d{(p a;a+=d)while a.send b,c}

A pretty straightforward solution. Unlike Value Ink's Ruby solution b doesn't have to be a Ruby symbol; just ints and a string/char as per the challenge. And it's still a byte under :)

Try it online

\$\endgroup\$
1
\$\begingroup\$

VBA, 87 Bytes

subroutine that does the thing

Sub f(a,b,c,d)
While IIf(b="<",a<c,a>c)
Debug.?a
a=a+d
Wend
End Sub
\$\endgroup\$
0
\$\begingroup\$

APL (Dyalog), 19 bytes

{⍵⍺⍺⍨⊃⍺:⋄⍺∇2⊃⍺+⎕←⍵}

This is an operator taking (c,d) as left argument, b as left operand, and a as right argument.

{ anonymous "something"

 [if] the right argument

⍺⍺⍨ is not ber than (also signals that this is an operator)

⊃⍺ the first of the left arguments

: then terminate

else

⍺∇ reuse the left argument to call the derived function (this operator with its operand) on

2⊃ the second element of

⍺+ the left argument added to

⎕← the printed

 right argument

}

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Excel VBA, 47 Bytes

Anonymous VBE immediate window function that takes input as described in prompt from the range [A1:D1] on the ActiveSheet object and implicitly outputs back onto that object by modifying the value of the visible [A1].Value variable

While[If(B1="<",A1<C1,A1>C1)]:[A1]=[A1+D1]:Wend
\$\endgroup\$
1
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.