General FizzBuzz: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|AWK}}: tweaks to output-format)
Line 51: Line 51:
* the custom program is run, and does the actual work to output the desired result
* the custom program is run, and does the actual work to output the desired result


;Input:
<lang bash>awk -f fizzbuzzGenerate.awk input.txt > fizzbuzzCustom.awk
awk -f fizzbuzzCustom.awk numbers.txt</lang>

;Input:
<pre>
<pre>
105
105
Line 61: Line 58:
7 Baxx
7 Baxx
</pre>
</pre>

<lang bash>awk -f fizzbuzzGenerate.awk input.txt > fizzbuzzCustom.awk
awk -f fizzbuzzCustom.awk numbers.txt</lang>


<!-- http://ideone.com/fACMfK -->
<!-- http://ideone.com/fACMfK -->
Line 87: Line 87:


END {
END {
print "x==" q2 q2 " {print $0; next}"
print "!x {print $1; next}"
print " {print " q2 "\\t" q2 " x; x=" q2 q2 "}"
print " {print " q2 " " q2 ", x; x=" q2 q2 "}"

print "END {print "q2"# Done."q2"}"
print "END {print "q2"# Done."q2"}"
print "# Done."
print "# Done."

Revision as of 01:58, 20 September 2015

Task
General FizzBuzz
You are encouraged to solve this task according to the task description, using any language you may know.

Write a generalized version of FizzBuzz that works for any list of factors, along with their words. This is basically a "fizzbuzz" implementation where the user supplies the parameters. The user will enter the max number, then they will enter the factors to be calculated along with the corresponding word to be printed. For simplicity's sake, assume the user will be inputing an integer as the max number and 3 factors, each with a word associated with them.

For example, given:

>20      #This is the maximum number, supplied by the user
>3 Fizz  #The user now enters the starting factor (3) and the word they want associated with it (Fizz)
>5 Buzz  #The user now enters the next factor (5) and the word they want associated with it (Buzz)
>7 Baxx  #The user now enters the next factor (7) and the word they want associated with it (Baxx)

In other words: For this example, print the numbers 1 through 20, replacing every multiple of 3 with "Fizz", every multiple of 5 with "Buzz", and every multiple of 7 with "Baxx". In the case where a number is a multiple of at least two factors, print each of the words associated with those factors in the order of least to greatest factor. For instance, the number 15 is a multiple of both 3 and 5; print "FizzBuzz". If the max number was 105 instead of 20, you would print "FizzBuzzBaxx" because it's a multiple of 3, 5, and 7.

Output:
1
2
Fizz
4
Buzz
Fizz
Baxx
8
Fizz
Buzz
11
Fizz
13
Baxx
FizzBuzz
16
17
Fizz
19
Buzz

AWK

This is a two-step solution:

  • First, we get the parameters, and
    • generate a file with the list of numbers (writing directly to that file)
    • generate a custom awk-program for that special case (redirecting standard-output)
  • the custom program is run, and does the actual work to output the desired result
Input
105
3 Fizz
5 Buzz
7 Baxx

<lang bash>awk -f fizzbuzzGenerate.awk input.txt > fizzbuzzCustom.awk awk -f fizzbuzzCustom.awk numbers.txt</lang>

<lang awk># usage: awk -f fizzbuzzGen.awk > fizzbuzzCustom.awk

BEGIN { print "# Generate:"

       q2 = "\""
       fN = "numbers.txt"
      #fP = "fizzbuzzCustom.awk"

}

NF==1 { print "#", $1, "Numbers:"

        for( i=1; i <= $1; i++ )
          print( i ) > fN          # (!!)
        print "# Custom program:"
        print "BEGIN {print " q2 "# CustomFizzBuzz:" q2 "}"
        next

}

NF==2 { #print "#", $1 "-->" $2 ##

        print "$1 %  "$1" == 0 {x = x "q2  $2 q2 "}"
        next

}

END {

    print "!x  {print $1; next}"
    print "    {print " q2 " " q2 ", x; x=" q2 q2 "}"
    print "END {print "q2"# Done."q2"}"
    print "# Done."

}</lang>

Example output see FizzBuzz/AWK#Custom_FizzBuzz

Batch File

<lang dos>@echo off setlocal enabledelayedexpansion ::Range variable set range=20

::The input data [will not be validated] ::This is the strictly the data format... set "data=3:Fizz 5:Buzz 7:Baxx"

::Parsing the data into 1-based pseudo-arrays... set "data_cnt=0" for %%A in (!data!) do ( set /a "data_cnt+=1" for /f "tokens=1-2 delims=:" %%D in ("%%A") do ( set "fact!data_cnt!=%%D" set "prnt!data_cnt!=%%E" ) )

::Do the count... for /l %%C in (1,1,!range!) do ( set "out=" for /l %%. in (1,1,!data_cnt!) do ( set /a "mod=%%C %% fact%%." if !mod! equ 0 ( set "out=!out!!prnt%%.!" ) ) if not defined out (echo.%%C) else (echo.!out!) ) pause exit /b 0</lang>

Output:
1
2
Fizz
4
Buzz
Fizz
Baxx
8
Fizz
Buzz
11
Fizz
13
Baxx
FizzBuzz
16
17
Fizz
19
Buzz
Press any key to continue . . .

C++

<lang cpp>

  1. include <algorithm>
  2. include <iostream>
  3. include <vector>
  4. include <string>

class pair { public:

   pair( int s, std::string z )            { p = std::make_pair( s, z ); }
   bool operator < ( const pair& o ) const { return i() < o.i(); }
   int i() const                           { return p.first; }
   std::string s() const                   { return p.second; }

private:

   std::pair<int, std::string> p;

}; void gFizzBuzz( int c, std::vector<pair>& v ) {

   bool output;
   for( int x = 1; x <= c; x++ ) {
       output = false;
       for( std::vector<pair>::iterator i = v.begin(); i != v.end(); i++ ) {
           if( !( x % ( *i ).i() ) ) {
               std::cout << ( *i ).s();
               output = true;
           }
       }
       if( !output ) std::cout << x;
       std::cout << "\n";
   }

} int main( int argc, char* argv[] ) {

   std::vector<pair> v;
   v.push_back( pair( 7, "Baxx" ) );
   v.push_back( pair( 3, "Fizz" ) );
   v.push_back( pair( 5, "Buzz" ) );
   std::sort( v.begin(), v.end() );
   gFizzBuzz( 20, v );
   return 0;

} </lang>

Output:
1
2
Fizz
4
Buzz
Fizz
Baxx
8
Fizz
Buzz
11
Fizz
13
Baxx
FizzBuzz
16
17
Fizz
19
Buzz

Clojure

<lang Clojure>(defn fix [pairs]

 (map second pairs))

(defn getvalid [pairs n]

 (filter (fn [p] (zero? (mod n (first p))))
         (sort-by first pairs)))

(defn gfizzbuzz [pairs numbers]

 (interpose "\n"
            (map (fn [n] (let [f (getvalid pairs n)]
                           (if (empty? f)
                             n
                             (apply str
                                    (fix f)))))
                 numbers)))</lang>

Usage:

user#=> (def pairs [[5 "Buzz"] [3 "Fizz"] [7 "Baxx"]])
#'user/pairs
user#=> (println (apply str (gfizzbuzz pairs (range 1 21))))
1
2
Fizz
4
Buzz
Fizz
Baxx
8
Fizz
Buzz
11
Fizz
13
Baxx
FizzBuzz
16
17
Fizz
19
Buzz
nil

Elixir

Translation of: Ruby

<lang elixir>defmodule General do

 def fizzbuzz(input) do
   [num | nwords] = String.split(input)
   max = String.to_integer(num)
   dict = Enum.chunk(nwords, 2) |> Enum.map(fn[n,word] -> {String.to_integer(n),word} end)
   Enum.each(1..max, fn i ->
     str = Enum.map_join(dict, fn {n,word} -> if rem(i,n)==0, do: word end)
     IO.puts if str=="", do: i, else: str
   end)
 end

end

input = """ 105 3 Fizz 5 Buzz 7 Baxx """ General.fizzbuzz(input)</lang>

Output:
1
2
Fizz
4
Buzz
Fizz
Baxx
8
Fizz
Buzz
11
Fizz
13
Baxx
FizzBuzz
16
17
Fizz
19
Buzz
FizzBaxx
...
Buzz
101
Fizz
103
104
FizzBuzzBaxx

Haskell

<lang haskell>fizz :: (Integral a, Show a) => a -> [(a, String)] -> String fizz a xs

   | null result = show a
   | otherwise   = result
   where result = concatMap (fizz' a) xs
         fizz' a (factor, str)
             | a `mod` factor == 0 = str
             | otherwise           = ""

main = do

   line <- getLine
   let n = read line
   contents <- getContents
   let multiples = map (convert . words) $ lines contents
   mapM_ (\ x -> putStrLn $ fizz x multiples) [1..n]
   where convert [x, y] = (read x, y)

</lang>

J

The trick here involves looking for where the factors evenly divide the counting numbers. Where no factor is relevant we use the counting number, an in the remaining cases we use the string which corresponds to the factor:

<lang J>genfb=:1 :0

 b=. * x|/1+i.y
 >,&":&.>/(m#inv"_1~-.b),(*/b)#&.>1+i.y

)</lang>

Example use:

<lang J> 3 5 7 ('Fizz';'Buzz';'Baxx')genfb 20 1 2 Fizz 4 Buzz Fizz Baxx 8 Fizz Buzz 11 Fizz 13 Baxx FizzBuzz 16 17 Fizz 19 Buzz </lang>

For our example, b looks like this:

<lang J>1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 1 1 1 1 0 1 1 1 1 0 1 1 1 1 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1</lang>

*/b gives us 1s where we want numbers and 0s where we want to plug in the strings:

<lang J> */*3 5 7|/1+i.20 1 1 0 1 0 0 0 1 0 0 1 0 1 0 0 1 1 0 1 0</lang>

m is our strings, and #inv expands values out to match a selection. So, in our example, m#inv"_1~-.b looks like this:

<lang J>┌┬┬────┬┬────┬────┬────┬┬────┬────┬┬────┬┬────┬────┬┬┬────┬┬────┐ │││Fizz││ │Fizz│ ││Fizz│ ││Fizz││ │Fizz│││Fizz││ │ ├┼┼────┼┼────┼────┼────┼┼────┼────┼┼────┼┼────┼────┼┼┼────┼┼────┤ │││ ││Buzz│ │ ││ │Buzz││ ││ │Buzz│││ ││Buzz│ ├┼┼────┼┼────┼────┼────┼┼────┼────┼┼────┼┼────┼────┼┼┼────┼┼────┤ │││ ││ │ │Baxx││ │ ││ ││Baxx│ │││ ││ │ └┴┴────┴┴────┴────┴────┴┴────┴────┴┴────┴┴────┴────┴┴┴────┴┴────┘</lang>

All that remains is to assemble these pieces into the final result...

Java

<lang java>public class FizzBuzz {

   public static void main(String[] args) {
       Sound[] sounds = {new Sound(3, "Fizz"), new Sound(5, "Buzz"),  new Sound(7, "Baxx")};
       for (int i = 1; i <= 20; i++) {
           StringBuilder sb = new StringBuilder();
           for (Sound sound : sounds) {
               sb.append(sound.generate(i));
           }
           System.out.println(sb.length() == 0 ? i : sb.toString());
       }
   }
   private static class Sound {
       private final int trigger;
       private final String onomatopoeia;
       public Sound(int trigger, String onomatopoeia) {
           this.trigger = trigger;
           this.onomatopoeia = onomatopoeia;
       }
       public String generate(int i) {
           return i % trigger == 0 ? onomatopoeia : "";
       }
   }

}</lang>

JavaScript

In a functional style of JavaScript, with two nested reduce folds – one through the integer series, and one through the series of rules.

First as compacted by Google's Closure compiler: <lang JavaScript>function fizz(d, e) {

 return function b(a) {
   return a ? b(a - 1).concat(a) : [];
 }(e).reduce(function (b, a) {
   return b + (d.reduce(function (b, c) {
     return b + (a % c[0] ? "" : c[1]);
   }, "") || a.toString()) + "\n";
 }, "");

}</lang>

and then in the original expanded form, for better legibility:

<lang JavaScript>function fizz(lstRules, lngMax) {

   return (
       function rng(i) {
           return i ? rng(i - 1).concat(i) : []
       }
   )(lngMax).reduce(
       function (strSeries, n) {
           // The next member of the series of lines:
           // a word string or a number string
           return strSeries + (
               lstRules.reduce(
                   function (str, tplNumWord) {
                       return str + (
                           n % tplNumWord[0] ?  : tplNumWord[1]
                       )
                   }, 
               ) || n.toString()
           ) + '\n';
           
       }, 
   );

}

fizz([[3, 'Fizz'], [5, 'Buzz'], [7, 'Baxx']], 20);</lang>

Output:
1
2
Fizz
4
Buzz
Fizz
Baxx
8
Fizz
Buzz
11
Fizz
13
Baxx
FizzBuzz
16
17
Fizz
19
Buzz

Perl

<lang perl>

  1. !bin/usr/perl

use 5.020; use strict; use warnings;

  1. Get a max number from the user

say("Please enter the maximum possible multiple. "); my $max = <STDIN>;

  1. Get the factors from the user

my @factors = (); my $buffer; say("Now enter the first factor and its associated word. Ex: 3 Fizz "); chomp($buffer = <STDIN>); push @factors, $buffer; say("Now enter the second factor and its associated word. Ex: 5 Buzz "); chomp($buffer = <STDIN>); push @factors, $buffer; say("Now enter the third factor and its associated word. Ex: 7 Baxx "); chomp($buffer = <STDIN>); push @factors, $buffer;

  1. Counting from 1 to max

for(my $i = 1; $i <= $max; $i++) {

   #Create a secondary buffer as well as set the original buffer to the current index
   my $oBuffer;
   $buffer = $i;
   #Run through each element in our array
   foreach my $element (@factors)
   {
       #Look for white space
       $element =~ /\s/;
       #If the int is a factor of max, append it to oBuffer as a string to be printed
       if($i % substr($element, 0, @-) == 0)
       {
           $oBuffer = $oBuffer . substr($element, @+ + 1, length($element));
           #This is essentially setting a flag saying that at least one element is a factor
           $buffer = "";
       }
   }
   #If there are any factors for that number, print their words. If not, print the number.
   if(length($buffer) > 0)
   {
       print($buffer . "\n");
   }
   else
   {
       print($oBuffer . "\n");
   }

} </lang>

Output:
Please enter the maximum possible multiple. 
20
Now enter the first factor and its associated word. Ex: 3 Fizz 
3 Fizz
Now enter the second factor and its associated word. Ex: 5 Buzz 
5 Buzz
Now enter the third factor and its associated word. Ex: 7 Baxx 
7 Baxx
1
2
Fizz
4
Buzz
Fizz
Baxx
8
Fizz
Buzz
11
Fizz
13
Baxx
FizzBuzz
16
17
Fizz
19
Buzz

Perl 6

<lang perl6># General case implementation of a "FizzBuzz" class.

  1. Defaults to standard FizzBuzz unless a new schema is passed in.

class FizzBuzz {

   has $.schema is rw = < 3 Fizz 5 Buzz >.hash;
   method filter (Int $this) {
       my $fb;
       for $.schema.sort: { +.key } -> $p { $fb ~= $this %% +$p.key ?? $p.value !! };
       return $fb || $this;
   }

}


  1. Sub implementing the specific requirements of the task.

sub GeneralFizzBuzz (Int $upto, @schema?) {

   my $ping = FizzBuzz.new;
   $ping.schema = @schema.hash if @schema;
   map { $ping.filter: $_ }, 1 .. $upto;

}

  1. The task

say 'Using: 20 ' ~ <3 Fizz 5 Buzz 7 Baxx>; .say for GeneralFizzBuzz(20, <3 Fizz 5 Buzz 7 Baxx>);

say ;

  1. And for fun

say 'Using: 21 ' ~ <2 Pip 4 Squack 5 Pocketa 7 Queep>; say join ', ', GeneralFizzBuzz(21, <2 Pip 4 Squack 5 Pocketa 7 Queep>);</lang>

Output:
Using: 20 3 Fizz 5 Buzz 7 Baxx
1
2
Fizz
4
Buzz
Fizz
Baxx
8
Fizz
Buzz
11
Fizz
13
Baxx
FizzBuzz
16
17
Fizz
19
Buzz

Using: 21 2 Pip 4 Squack 5 Pocketa 7 Queep
1, Pip, 3, PipSquack, Pocketa, Pip, Queep, PipSquack, 9, PipPocketa, 11, PipSquack, 13, PipQueep, Pocketa, PipSquack, 17, Pip, 19, PipSquackPocketa, Queep

PowerShell

<lang powershell>$limit = 20 $data = @("3 Fizz","5 Buzz","7 Baxx") #An array with whitespace as the delimiter #Between the factor and the word

for ($i = 1;$i -le $limit;$i++){ $outP = "" foreach ($x in $data){ $data_split = $x -split " " #Split the "<factor> <word>" if (($i % $data_split[0]) -eq 0){ $outP += $data_split[1] #Append the <word> to outP } } if(!$outP){ #Is outP equal to NUL? Write-HoSt $i } else { Write-HoSt $outP } }</lang>

Output:
PS> ./GENFB
1
2
Fizz
4
Buzz
Fizz
Baxx
8
Fizz
Buzz
11
Fizz
13
Baxx
FizzBuzz
16
17
Fizz
19
Buzz
PS>

Python

<lang python>def genfizzbuzz(factorwords, numbers):

   factorwords.sort(key=lambda p: p[0])
   lines = []
   for num in numbers:
       words = .join(wrd for fact, wrd in factorwords if (num % fact) == 0)
       lines.append(words if words else str(num))
   return '\n'.join(lines)

if __name__ == '__main__':

   print(genfizzbuzz([(5, 'Buzz'), (3, 'Fizz'), (7, 'Baxx')], range(1, 21)))</lang>
Output:
1
2
Fizz
4
Buzz
Fizz
Baxx
8
Fizz
Buzz
11
Fizz
13
Baxx
FizzBuzz
16
17
Fizz
19
Buzz

Racket

Translation of: Python

<lang Racket>#lang racket/base

(define (get-matches num factors/words)

 (for*/list ([factor/word (in-list factors/words)]
             [factor (in-value (car factor/word))]
             [word (in-value (cadr factor/word))] 
             #:when (zero? (remainder num factor)))
   word))

(define (gen-fizzbuzz from to factors/words)

 (for ([num (in-range from to)])
   (define matches (get-matches num factors/words))
   (displayln (if (null? matches)
                 (number->string num)
                 (apply string-append matches)))))

(gen-fizzbuzz 1 21 '((3 "Fizz")

                    (5 "Buzz")
                    (7 "Baxx")))</lang>
Output:
1
2
Fizz
4
Buzz
Fizz
Baxx
8
Fizz
Buzz
11
Fizz
13
Baxx
FizzBuzz
16
17
Fizz
19
Buzz

REXX

<lang rexx>/*REXX program shows a generalized FizzBuzz program: #1 name1 #2 name2 ··· */ parse arg h $ /*get optional arguments from the C.L. */ if h= then h=20 /*Not specified? Then use the default.*/ if $= then $='3 Fizz 5 Buzz 7 Baxx' /* " " " " " " */ factors=words($)%2 /*Determine number of factors to use. */

   do i=1  for factors by 2           /*parse the number factors to be used. */
   #.i=word($,i);   @.i=word($,i+1)   /*obtain the factor and its  "name".   */
   end   /*i*/
   do j=1  for h;   _=                /*traipse through the numbers to   H.  */
     do k=1  for factors  by 2        /*   "       "     " factors  in   J.  */
     if j//#.k==0  then _=_ || @.k    /*Is it a factor?  Then append it to _ */
     end   /*k*/                      /* [↑]  Note:  the factors may be null.*/
   say word(_ j,1)                    /*display the number  or  its factors. */
   end     /*j*/
                                      /*stick a fork in it,  we're all done. */</lang>
Output:
1
2
Fizz
4
Buzz
Fizz
Baxx
8
Fizz
Buzz
11
Fizz
13
Baxx
FizzBuzz
16
17
Fizz
19
Buzz

Ruby

<lang ruby>def general_fizzbuzz(text)

 num, *nword = text.split
 num = num.to_i
 dict = nword.each_slice(2).map{|n,word| [n.to_i,word]}
 (1..num).each do |i|
   str = dict.map{|n,word| word if i%n==0}.join
   puts str.empty? ? i : str
 end

end

text = <<EOS 20 3 Fizz 5 Buzz 7 Baxx EOS

general_fizzbuzz(text)</lang>

Output:
1
2
Fizz
4
Buzz
Fizz
Baxx
8
Fizz
Buzz
11
Fizz
13
Baxx
FizzBuzz
16
17
Fizz
19
Buzz

Rust

<lang rust>use std::io; use std::io::BufRead;

fn parse_entry(l: &str) -> (i32, String) { let params: Vec<&str> = l.split(' ').take(2).collect();

let divisor = params[0].parse::<i32>().unwrap(); let word = params[1].to_string(); (divisor, word) }

fn main() { let stdin = io::stdin(); let mut lines = stdin.lock().lines().map(|l| l.unwrap());

let l = lines.next().unwrap(); let high = l.parse::<i32>().unwrap();

let mut entries = Vec::new(); for l in lines { let entry = parse_entry(&l); entries.push(entry); }

for i in 1..(high + 1) { let mut line = String::new(); for &(divisor, ref word) in &entries { if i % divisor == 0 { line = line + &word; } } if line == "" { println!("{}", i); } else { println!("{}", line); } } }</lang>

Sidef

<lang ruby>class FizzBuzz(schema=Hash.new(<3 Fizz 5 Buzz>...)) {

   method filter(this) {
       var fb = ;
       schema.sort_by {|k,_| k.to_i }.each { |pair|
           fb += (this %% pair[0] ? pair[1] : );
       };
       fb.len > 0 ? fb : this;
   }

}

func GeneralFizzBuzz(upto, schema) {

   var ping = FizzBuzz();
   nil != schema && (
       ping.schema = schema.to_hash;
   );
   upto.of {|i| ping.filter(i) };

}

GeneralFizzBuzz(20, <3 Fizz 5 Buzz 7 Baxx>).each { .say };</lang>

Output:
1
2
Fizz
4
Buzz
Fizz
Baxx
8
Fizz
Buzz
11
Fizz
13
Baxx
FizzBuzz
16
17
Fizz
19
Buzz

Tcl

Tcl excels at metaprogramming, so this task is trivial. For fun, the below implementation is a compatible extension of FizzBuzz#Tcl:

<lang Tcl>proc fizzbuzz {n args} {

   if {$args eq ""} {
       set args {{3 Fizz} {5 Buzz}}
   }
   while {[incr i] <= $n} {
       set out ""
       foreach rule $args {
           lassign $rule m echo
           if {$i % $m == 0} {append out $echo}
       }
       if {$out eq ""} {set out $i}
       puts $out
   }

} fizzbuzz 20 {3 Fizz} {5 Buzz} {7 Baxx}</lang>

VBScript

This example is incorrect. Please fix the code and remove this message.

Details: Mappings are supposed to be parameterized, not hardwired as they are here.

<lang vb>Function fizzbuzz(n) If n Mod 3 = 0 Then fizzbuzz = fizzbuzz & "Fizz" End If If n Mod 5 = 0 Then fizzbuzz = fizzbuzz & "Buzz" End If If n Mod 7 = 0 Then fizzbuzz = fizzbuzz & "Baxx" End If If fizzbuzz = "" Then fizzbuzz = n End If End Function

'testing For i = 1 To 20 WScript.StdOut.WriteLine i & " " & fizzbuzz(i) Next </lang>

Output:
1 1
2 2
3 Fizz
4 4
5 Buzz
6 Fizz
7 Baxx
8 8
9 Fizz
10 Buzz
11 11
12 Fizz
13 13
14 Baxx
15 FizzBuzz
16 16
17 17
18 Fizz
19 19
20 Buzz