Page 1 of 2

FizzBuzz

Posted: Sun 18 Nov 2012, 05:32
by GustavoYz
I surprised myself reading this.
Is likely a very easy challenge, but effective somehow. :shock:

Im wondering if there is a bash solution (one line, not a script) shorter than this mess I just did :lol: :

Code: Select all

for nn in `seq 1 100`;  do { [ $(( $nn % 15 )) == 0 ] && echo "FizzBuzz"; } || { [ $(( $nn % 5 )) == 0 ] && echo "Buzz"; } || { [ $(( $nn % 3 )) == 0 ] && echo "Fizz"; } || ( echo "$nn") ; done  | column
Although is like "cheat" on this context, my Perl solution end up being (way) shorter:

Code: Select all

perl -E 'say $_ % 15 ? $_ % 3 ? $_ % 5 ? "$_" : "Buzz" : "Fizz" : "Fizzbuzz" for 1 .. 100 ' | column
(note that both commands are piped to `column` for easy reading, not essential).

:?: As I know that there is a lot of Bash wisdom surrounding, I'm wondering, are there better/shorter(/prettier) Bash ways?

Re: FizzBuzz

Posted: Sun 18 Nov 2012, 09:04
by jamesbond
GustavoYz wrote:Im wondering if there is a bash solution (one line, not a script) shorter than this mess I just did :lol: :

Code: Select all

for nn in `seq 1 100`;  do { [ $(( $nn % 15 )) == 0 ] && echo "FizzBuzz"; } || { [ $(( $nn % 5 )) == 0 ] && echo "Buzz"; } || { [ $(( $nn % 3 )) == 0 ] && echo "Fizz"; } || ( echo "$nn") ; done  | column
That's just "sh" not "bash". This is bash:

Code: Select all

for ((a=1; a <= 100; a++)); do ! ((a%15)) && echo FizzBuzz || ! ((a%3)) && echo Fizz ||  ! ((a%5)) && echo Buzz ||  echo $a; done | column
I'm sure technosaurus can make it even shorter 8)

Re: FizzBuzz

Posted: Sun 18 Nov 2012, 19:00
by GustavoYz
jamesbond wrote:
GustavoYz wrote:Im wondering if there is a bash solution (one line, not a script) shorter than this mess I just did :lol: :

Code: Select all

for nn in `seq 1 100`;  do { [ $(( $nn % 15 )) == 0 ] && echo "FizzBuzz"; } || { [ $(( $nn % 5 )) == 0 ] && echo "Buzz"; } || { [ $(( $nn % 3 )) == 0 ] && echo "Fizz"; } || ( echo "$nn") ; done  | column
That's just "sh" not "bash". This is bash:

Code: Select all

for ((a=1; a <= 100; a++)); do ! ((a%15)) && echo FizzBuzz || ! ((a%3)) && echo Fizz ||  ! ((a%5)) && echo Buzz ||  echo $a; done | column
And that's incorrect...
:roll:

I appreciate the reply, but your "Bash" way is grouping the || and && in the wrong way and you have more than 100 items on that...

Posted: Sun 18 Nov 2012, 19:39
by rcrsn51
Is the objective to have the least amount of code or the least amount of computation?

Posted: Sun 18 Nov 2012, 20:04
by GustavoYz
rcrsn51 wrote:Is the objective to have the least amount of code or the least amount of computation?
I would like to learn a "better" way of achieve the same on the shell (trough Bash or sh) if is possible.
If two versions of the same command, working equally well and at comparable speed, i'd prefer the shorter and/or mnemonic.

Re: FizzBuzz

Posted: Sun 18 Nov 2012, 22:51
by jamesbond
GustavoYz wrote: And that's incorrect...
:roll:
That was an optimisation went wrong. My original version looked like this before I tried to over-optimise and remove the "continue" with || ... :lol:

Code: Select all

time for ((a=1; a <= 100; a++)); do ! ((a%15)) && echo FizzBuzz && continue; ! ((a%3)) && echo Fizz && continue;  ! ((a%5)) && echo Buzz && continue;  echo $a; done 

Re: FizzBuzz

Posted: Mon 19 Nov 2012, 18:09
by GustavoYz
jamesbond wrote:

Code: Select all

time for ((a=1; a <= 100; a++)); do ! ((a%15)) && echo FizzBuzz && continue; ! ((a%3)) && echo Fizz && continue;  ! ((a%5)) && echo Buzz && continue;  echo $a; done 
Thanks!
:P

FizzBuzz

Posted: Wed 21 Nov 2012, 16:03
by L18L
Before this thread is SOLVED another FizzBuzz
not fast
not short
but python

Code: Select all

for a in range(1,101):
    if  a % 15 == 0:
        print 'FizzBuzz'
        continue
    if a %  5 == 0:
        print 'Fizz'
        continue
    if a %  3 == 0:
        print 'Buzz'
        continue
    print a 
or 2 lines less but slower:

Code: Select all

for a in range(1,101):
    if  a % 15 == 0:
        print 'FizzBuzz'
    elif a %  5 == 0:
        print 'Fizz'
    elif a %  3 == 0:
        print 'Buzz'
    else:
        print a 
or:

Code: Select all

for a in range(1,101):
    p = ''
    if not a % 5 : p += 'Fizz'
    if not a % 3 : p += 'Buzz'
    if not p : p  = a		    
    print p 
Why learn bash if....

Posted: Wed 21 Nov 2012, 18:16
by GustavoYz
Well, I wasn't after a python script or solution and my question was about 'one-liners', but thanks a lot anyway.
I solved it on python time ago (using the interpreter originally) with this code:

Code: Select all

python -c 'print ["Fizz"[i%3*4:]+"Buzz"[i%5*4:]or str(i)for i in range(1,101)]'
but found plenty python versions that taught me better ways...
Why learn bash if....
Lots of reasons... Quick one? There is not such thing as a python shell yet, to replace actual Bash/sh/zsh or even tclsh. :roll:
Buy Python is great, no discussions on that (I've to deal with it everyday :) )

I am (still) curious about how much less code is possible to solve the task in the shell (Bash or Sh).

FizzBuzz

Posted: Wed 21 Nov 2012, 19:09
by L18L
GustavoYz wrote:I am (still) curious about how much less code is possible to solve the task in the shell (Bash or Sh).
not less but fast:
a one liner in my console wrote:# time i=0;while [ $i -lt 100 ];do i=$(($i+1));p='';[[ $((i%3)) -eq 0 ]] && p='Fizz';[[ $((i%5)) -eq 0 ]] && p="${p}Buzz";[ "$p" ]|| p=$i;echo -n "$p ";done

real 0m0.000s
user 0m0.000s
sys 0m0.000s
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34 Buzz Fizz 37 38 Fizz Buzz 41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz Fizz 52 53 Fizz Buzz 56 Fizz 58 59 FizzBuzz 61 62 Fizz 64 Buzz Fizz 67 68 Fizz Buzz 71 Fizz 73 74 FizzBuzz 76 77 Fizz 79 Buzz Fizz 82 83 Fizz Buzz 86 Fizz 88 89 FizzBuzz 91 92 Fizz 94 Buzz Fizz 97 98 Fizz Buzz #

Posted: Thu 22 Nov 2012, 01:54
by GustavoYz
Thanks. :D

Posted: Mon 26 Nov 2012, 07:18
by technosaurus
that was about what I had too

Code: Select all

n=0;s="";b="";while [ $((n)) != 100 ]; do b="";n=$(($n+1));[ $(($n%3)) == 0 ] && b=Fizz;[ $(($n%5)) == 0 ] && b=${b}Buzz"
";[ "$b" ] && s=$s"	"$b || s=$s"	"$n;done;echo "$s"
prints out 5 tab separated columns using only basic shell

Note it is normally much faster to echo $s (without formatting) than "$s" (with formatting)

or some variation of

Code: Select all

n=0;s="";while [ $(($n)) != 100 ];do n=$(($n+1));case $(($n%15)) in 3|6|9|12)s=$s"	"Fizz;;5|10)s=$s"	"Buzz"
";;0)s=$s"	"FizzBuzz"
";;*)s=$s"	"$n;;esac;done;echo "$s"
creating the string only takes ~ 0.01s on my box while outputting it to the console takes ~0.05 ... output to a file reduces this to ~0.002s though

with bashisms it could be simplified to

Code: Select all

n=0;s="";while [ $((n++)) != 100 ];do case $(($n%15)) in 3|6|9|12)s=$s"	"Fizz;;5|10)s=$s"	"Buzz"
";;0)s=$s"	"FizzBuzz"
";;*)s=$s"	"$n;;esac;done;echo "$s"

Posted: Mon 26 Nov 2012, 11:49
by linuph
technosaurus:
that's 0.03 user seconds on my P3 1GHz with echo to console, 0.02 with echo to file

Posted: Mon 26 Nov 2012, 13:37
by technosaurus
here is the C for comparison

Code: Select all

#include <stdio>

int void main(){
int n=0;

while (n++ < 100){
switch (n%15){
case 3 :
case 6 :
case 9 :
case 12 :
printf("Fizz\t");
break;
case 5 :
case 10 :
printf("Buzz\n");
break;
case 0 :
printf("FizzBuzz\n");
break;
default :
printf("%d\t",n);
}
}

}

Posted: Mon 26 Nov 2012, 16:22
by rcrsn51
technosaurus wrote:

Code: Select all

switch (n%15){
Very nice. Doing three divisions is clearly overkill. Doing one division is better.

Posted: Mon 26 Nov 2012, 17:27
by technosaurus
rcrsn51 wrote:
technosaurus wrote:

Code: Select all

switch (n%15){
Very nice. Doing three divisions is clearly overkill. Doing one division is better.
Its not exactly a duff's device, but that is what I was recalling as a template.

Posted: Mon 26 Nov 2012, 17:39
by GustavoYz
@technosaurus: Nice, thanks. :D

Posted: Tue 27 Nov 2012, 08:30
by jamesbond
rcrsn51 wrote:Very nice. Doing three divisions is clearly overkill. Doing one division is better.
I have one that does not use division at all; but surprisingly it is slower :shock:

Code: Select all

for ((a=1,b=2,c=4;a<101;a++,b--,c--));do d=$a;((\!b && \!c))&&d=FizzBuzz b=3 c=5;((\!b))&&d=Fizz b=3;((\!c))&&d=Buzz c=5;echo $d; done

Posted: Tue 27 Nov 2012, 16:12
by rcrsn51
jamesbond wrote:I have one that does not use division at all; but surprisingly it is slower
Is this an example of "loop unwinding"? Where the amount of processing needed to manage the loop is more than what's required to execute the contents of the loop?

So maybe three divisions is not a bad thing if it reduces the total amount of processing.

Posted: Tue 27 Nov 2012, 20:05
by technosaurus
here is an example how less comparisons can actually be bad

Code: Select all

#include <stdio.h>
	
int void main(){ 
int a=0,b=0,max=100;
char buf[500];
while(b<max/15){ //if max > 15 do blocks of 15 first
 printf("%d\t%d\tFizz\t%d\tBuzz\nFizz\t%d\t%d\tFizz\tBuzz\n%d\tFizz\t%d\t%d\tFizzBuzz\n",
		a+1,a+2,a+4,a+7,a+8,a+11,a+13,a+14);
 a=++b*15;
}
/* now do the remainder, but in order to do 1 comparison, we must reverse
 * this is _much_ slower than the comparisons so don't use it
 * - just an example of how using less comparisons can be slower
 * especially if doing so requires using additional slower functions
 * we don't always know what the compiler will do
*/
switch(max%15){
case 14 : sprintf(buf,"%d",a+14);
case 13 : sprintf(buf,"%d\t%s",a+13,buf);
case 12 : sprintf(buf,"Fizz\t%s",buf);
case 11 : sprintf(buf,"%d\t%s",a+11,buf);
case 10 : sprintf(buf,"Buzz\n%s",buf);
case 9 :  sprintf(buf,"Fizz\t%s",buf);
case 8 :  sprintf(buf,"%d\t%s",a+8,buf);
case 7 : sprintf(buf,"%d\t%s",a+7,buf);
case 6 : sprintf(buf,"Fizz\t%s",buf);
case 5 : sprintf(buf,"Buzz\n%s",buf);
case 4 : sprintf(buf,"%d\t%s",a+4,buf);
case 3 : sprintf(buf,"Fizz\t%s",buf);
case 2 : sprintf(buf,"%d\t%s",a+2,buf);
case 1 : sprintf(buf,"%d\t%s",a+1,buf);
default : break
}
printf("%s",buf);
} 

	return 0;
}
as opposed partial unwinding to something like:

Code: Select all

#include <stdio.h>
	
int main(){ 
int a=0,b=0,max=100;
while(b<max/15){ //if max > 15 do blocks of 15 first
	printf("%d\t%d\tFizz\t%d\tBuzz\nFizz\t%d\t%d\tFizz\tBuzz\n%d\tFizz\t%d\t%d\tFizzBuzz\n",a+1,a+2,a+4,a+7,a+8,a+11,a+13,a+14);
	a=++b*15;
}
while (a++ < 100){ 
	switch (a%15){ 
		case 3 : case 6 : case 9 : case 12 : printf("Fizz\t");break; 
		case 5 : case 10 : printf("Buzz\n"); break; 
		default : printf("%d\t",a);break;
	} 
} 

	return 0;
}
btw, you can do this same algorithm in shell