Last active
August 29, 2015 14:10
-
-
Save skriptble/5900fb7cc85f3b23f477 to your computer and use it in GitHub Desktop.
FizzBuzz with Transducers!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"github.com/sdboyer/transducers-go" | |
) | |
func FizzyBuzzyNumbers() transducers.ValueStream { | |
fizzyBuzzyCurr := 0 | |
return func() (value interface{}, done bool) { | |
if fizzyBuzzyCurr < 100 { | |
fizzyBuzzyCurr++ | |
return fizzyBuzzyCurr, false | |
} | |
return nil, true | |
} | |
} | |
func FizzyBuzzyEduction() transducers.ValueStream { | |
return transducers.Eduction(transducers.Range(100), transducers.Map(transducers.Inc)) | |
} | |
func main() { | |
stack := []transducers.Transducer{ | |
transducers.Map(FizzBuzzer), | |
transducers.Map(Buzzer), | |
transducers.Map(Fizzer), | |
} | |
reducer := StringAppend() | |
// result := transducers.Transduce(FizzyBuzzyNumbers(), reducer, stack...) | |
result := transducers.Transduce(FizzyBuzzyEduction(), reducer, stack...) | |
fmt.Println(result) | |
} | |
func Fizzer(value interface{}) interface{} { | |
num, ok := value.(int) | |
if !ok { | |
return value | |
} | |
if num%3 == 0 { | |
return "Fizz" | |
} | |
return value | |
} | |
func Buzzer(value interface{}) interface{} { | |
num, ok := value.(int) | |
if !ok { | |
return value | |
} | |
if num%5 == 0 { | |
return "Buzz" | |
} | |
return value | |
} | |
func FizzBuzzer(value interface{}) interface{} { | |
num, ok := value.(int) | |
if !ok { | |
return value | |
} | |
if num%3 == 0 && num%5 == 0 { | |
return "FizzBuzz" | |
} | |
return value | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"sort" | |
"strconv" | |
"time" | |
"github.com/sdboyer/transducers-go" | |
) | |
type io struct { | |
Input int | |
Output string | |
} | |
// Used for sorting at the end | |
type ByInput []io | |
func (in ByInput) Len() int { return len(in) } | |
func (in ByInput) Swap(i, j int) { in[i], in[j] = in[j], in[i] } | |
func (in ByInput) Less(i, j int) bool { return in[i].Input < in[j].Input } | |
func main() { | |
var numGoRoutines int | |
output := make(chan interface{}, 0) | |
done := make(chan interface{}, 0) | |
input := make(chan interface{}, 0) | |
slice := make([]io, 0) | |
fizzbuzz, fizz, buzz := make(chan interface{}, 0), make(chan interface{}, 0), make(chan interface{}, 0) | |
go aggregator(output, &slice) | |
go transducers.StreamIntoChan(IOStream(), input) | |
stack := []transducers.Transducer{ | |
transducers.Escape(FizzBuzzEscaper, fizzbuzz, true), | |
transducers.Escape(FizzEscaper, fizz, true), | |
transducers.Escape(BuzzEscaper, buzz, true), | |
transducers.Map(IORegular), | |
} | |
outs := []<-chan interface{}{ | |
transducers.Go(input, 0, stack...), | |
transducers.Go(fizzbuzz, 0, transducers.Map(IOFizzBuzzer)), | |
transducers.Go(fizz, 0, transducers.Map(IOFizzer)), | |
transducers.Go(buzz, 0, transducers.Map(IOBuzzer)), | |
} | |
numGoRoutines = len(outs) | |
for _, value := range outs { | |
go func(o chan<- interface{}, v <-chan interface{}, finished chan<- interface{}) { | |
for val := range v { | |
o <- val | |
} | |
finished <- struct{}{} | |
}(output, value, done) | |
} | |
numComplete := 0 | |
for { | |
select { | |
case <-done: | |
numComplete++ | |
} | |
if numComplete == numGoRoutines { | |
// Allow everything to finish being processed | |
time.Sleep(time.Millisecond) | |
break | |
} | |
} | |
close(output) | |
sort.Sort(ByInput(slice)) | |
for _, v := range slice { | |
fmt.Printf("%v\t", v.Output) | |
} | |
fmt.Printf("\n") | |
} | |
// aggregator accepts channel and appends the output of the channel to the slice | |
func aggregator(c <-chan interface{}, out *[]io) { | |
for val := range c { | |
*out = append(*out, val.(io)) | |
} | |
} | |
// IOMapper is a mapper to convert an int into an io | |
func IOMapper(value interface{}) interface{} { | |
return io{Input: value.(int)} | |
} | |
// IOStream produces the numbers | |
func IOStream() transducers.ValueStream { | |
return transducers.Eduction( | |
transducers.Range(100), | |
transducers.Map(transducers.Inc), | |
transducers.Map(IOMapper), | |
) | |
} | |
// FizzEscaper will return true if the Input field of an io struct is divisible | |
// by 3 | |
func FizzEscaper(value interface{}) bool { | |
num := value.(io).Input | |
if num%3 == 0 { | |
return true | |
} | |
return false | |
} | |
// BuzzEscaper will return true if the Input field of an io struct is divisible | |
// by 5 | |
func BuzzEscaper(value interface{}) bool { | |
num := value.(io).Input | |
if num%5 == 0 { | |
return true | |
} | |
return false | |
} | |
// BuzzEscaper will return true if the Input field of an io struct is divisible | |
// by both3 and 15 | |
func FizzBuzzEscaper(value interface{}) bool { | |
num := value.(io).Input | |
if num%3 == 0 && num%5 == 0 { | |
return true | |
} | |
return false | |
} | |
// IOFizzer will set the Output property of the io struct to Fizz | |
func IOFizzer(value interface{}) interface{} { | |
inOut := value.(io) | |
inOut.Output = "Fizz" | |
return inOut | |
} | |
// IOBuzzer will set the Output property of the io struct to Buzz | |
func IOBuzzer(value interface{}) interface{} { | |
inOut := value.(io) | |
inOut.Output = "Buzz" | |
return inOut | |
} | |
// IOFizzBuzzer will set the Output property of the io struct to FizzBuzz | |
func IOFizzBuzzer(value interface{}) interface{} { | |
inOut := value.(io) | |
inOut.Output = "FizzBuzz" | |
return inOut | |
} | |
// IORegular will set the Output property of the io struct to a string | |
// conversion of the Input property. | |
func IORegular(value interface{}) interface{} { | |
inOut := value.(io) | |
inOut.Output = strconv.Itoa(inOut.Input) | |
return inOut | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
For anyone wondering about the weird sleep call: For some reason getting the last buzz through the pipeline takes a little longer. This only seems to be true of 100, as when I used 101, 105, 110, and 200 this line wasn't necessary. Kudos if you can figure out what's up.