Skip to content

Instantly share code, notes, and snippets.

@skriptble
Last active August 29, 2015 14:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save skriptble/5900fb7cc85f3b23f477 to your computer and use it in GitHub Desktop.
Save skriptble/5900fb7cc85f3b23f477 to your computer and use it in GitHub Desktop.
FizzBuzz with Transducers!
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
}
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
}
@skriptble
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment