From dffca1483a90b766cb6fc6515195bfc5ea1bd731 Mon Sep 17 00:00:00 2001 From: yberman Date: Wed, 4 Oct 2017 03:20:54 -0400 Subject: [PATCH] Added permutations of finite iterators --- itertools.go | 148 +++++++++++++++++++++++++++++----------- itertools_bench_test.go | 9 +++ itertools_test.go | 91 ++++++++++++++---------- 3 files changed, 171 insertions(+), 77 deletions(-) diff --git a/itertools.go b/itertools.go index f31ef30..805896d 100644 --- a/itertools.go +++ b/itertools.go @@ -9,14 +9,14 @@ import ( ) type Iter chan interface{} -type Predicate func (interface{}) bool -type Mapper func (interface{}) interface{} -type MultiMapper func (...interface{}) interface{} -type Reducer func (memo interface{}, element interface{}) interface{} +type Predicate func(interface{}) bool +type Mapper func(interface{}) interface{} +type MultiMapper func(...interface{}) interface{} +type Reducer func(memo interface{}, element interface{}) interface{} -func New(els ... interface{}) Iter { +func New(els ...interface{}) Iter { c := make(Iter) - go func () { + go func() { for _, el := range els { c <- el } @@ -25,9 +25,9 @@ func New(els ... interface{}) Iter { return c } -func Int64(els ... int64) Iter { +func Int64(els ...int64) Iter { c := make(Iter) - go func () { + go func() { for _, el := range els { c <- el } @@ -36,9 +36,9 @@ func Int64(els ... int64) Iter { return c } -func Int32(els ... int32) Iter { +func Int32(els ...int32) Iter { c := make(Iter) - go func () { + go func() { for _, el := range els { c <- el } @@ -47,9 +47,9 @@ func Int32(els ... int32) Iter { return c } -func Float64(els ... float64) Iter { +func Float64(els ...float64) Iter { c := make(Iter) - go func () { + go func() { for _, el := range els { c <- el } @@ -58,9 +58,9 @@ func Float64(els ... float64) Iter { return c } -func Float32(els ... float32) Iter { +func Float32(els ...float32) Iter { c := make(Iter) - go func () { + go func() { for _, el := range els { c <- el } @@ -69,9 +69,9 @@ func Float32(els ... float32) Iter { return c } -func Uint(els ... uint) Iter { +func Uint(els ...uint) Iter { c := make(Iter) - go func () { + go func() { for _, el := range els { c <- el } @@ -79,9 +79,9 @@ func Uint(els ... uint) Iter { }() return c } -func Uint64(els ... uint64) Iter { +func Uint64(els ...uint64) Iter { c := make(Iter) - go func () { + go func() { for _, el := range els { c <- el } @@ -90,9 +90,9 @@ func Uint64(els ... uint64) Iter { return c } -func Uint32(els ... uint32) Iter { +func Uint32(els ...uint32) Iter { c := make(Iter) - go func () { + go func() { for _, el := range els { c <- el } @@ -112,7 +112,7 @@ func List(it Iter) []interface{} { // Count from i to infinity func Count(i int) Iter { c := make(Iter) - go func () { + go func() { for ; true; i++ { c <- i } @@ -123,7 +123,7 @@ func Count(i int) Iter { // Cycle through an iterator infinitely (requires memory) func Cycle(it Iter) Iter { c, a := make(Iter), make([]interface{}, 0, 1) - go func () { + go func() { for el := range it { a = append(a, el) c <- el @@ -140,7 +140,7 @@ func Cycle(it Iter) Iter { // Repeat an element n times or infinitely func Repeat(el interface{}, n ...int) Iter { c := make(Iter) - go func () { + go func() { for i := 0; len(n) == 0 || i < n[0]; i++ { c <- el } @@ -166,7 +166,7 @@ func Chain(its ...Iter) Iter { // Elements after pred(el) == true func DropWhile(pred Predicate, it Iter) Iter { c := make(Iter) - go func () { + go func() { for el := range it { if drop := pred(el); !drop { c <- el @@ -181,11 +181,10 @@ func DropWhile(pred Predicate, it Iter) Iter { return c } - // Elements before pred(el) == false func TakeWhile(pred Predicate, it Iter) Iter { c := make(Iter) - go func () { + go func() { for el := range it { if take := pred(el); take { c <- el @@ -201,7 +200,7 @@ func TakeWhile(pred Predicate, it Iter) Iter { // Filter out any elements where pred(el) == false func Filter(pred Predicate, it Iter) Iter { c := make(Iter) - go func () { + go func() { for el := range it { if keep := pred(el); keep { c <- el @@ -215,7 +214,7 @@ func Filter(pred Predicate, it Iter) Iter { // Filter out any elements where pred(el) == true func FilterFalse(pred Predicate, it Iter) Iter { c := make(Iter) - go func () { + go func() { for el := range it { if drop := pred(el); !drop { c <- el @@ -227,18 +226,18 @@ func FilterFalse(pred Predicate, it Iter) Iter { } // Sub-iterator from start (inclusive) to [stop (exclusive) every [step (default 1)]] -func Slice(it Iter, startstopstep...int) Iter { +func Slice(it Iter, startstopstep ...int) Iter { start, stop, step := 0, 0, 1 if len(startstopstep) == 1 { start = startstopstep[0] } else if len(startstopstep) == 2 { start, stop = startstopstep[0], startstopstep[1] - } else if len(startstopstep) >= 3 { + } else if len(startstopstep) >= 3 { start, stop, step = startstopstep[0], startstopstep[1], startstopstep[2] } c := make(Iter) - go func () { + go func() { i := 0 // Start for el := range it { @@ -250,15 +249,15 @@ func Slice(it Iter, startstopstep...int) Iter { } // Stop - i, j := i + 1, 1 + i, j := i+1, 1 for el := range it { if stop > 0 && i >= stop { break - } else if j % step == 0 { + } else if j%step == 0 { c <- el } - i, j = i + 1, j + 1 + i, j = i+1, j+1 } close(c) @@ -269,7 +268,7 @@ func Slice(it Iter, startstopstep...int) Iter { // Map an iterator to fn(el) for el in it func Map(fn Mapper, it Iter) Iter { c := make(Iter) - go func () { + go func() { for el := range it { c <- fn(el) } @@ -283,11 +282,11 @@ func Map(fn Mapper, it Iter) Iter { func MultiMap(fn MultiMapper, its ...Iter) Iter { c := make(Iter) go func() { -Outer: + Outer: for { els := make([]interface{}, len(its)) for i, it := range its { - if el, ok := <- it; ok { + if el, ok := <-it; ok { els[i] = el } else { break Outer @@ -309,7 +308,7 @@ func MultiMapLongest(fn MultiMapper, its ...Iter) Iter { els := make([]interface{}, len(its)) n := 0 for i, it := range its { - if el, ok := <- it; ok { + if el, ok := <-it; ok { els[i] = el } else { n += 1 @@ -353,7 +352,7 @@ func Zip(its ...Iter) Iter { for { els := make([]interface{}, len(its)) for i, it := range its { - if el, ok := <- it; ok { + if el, ok := <-it; ok { els[i] = el } else { return @@ -374,7 +373,7 @@ func ZipLongest(its ...Iter) Iter { els := make([]interface{}, len(its)) n := 0 for i, it := range its { - if el, ok := <- it; ok { + if el, ok := <-it; ok { els[i] = el } else { n += 1 @@ -415,7 +414,7 @@ func Tee(it Iter, n int) []Iter { if len(deques[i]) == 0 { mutex.Lock() if len(deques[i]) == 0 { - if newval, ok := <- it; ok { + if newval, ok := <-it; ok { for i, d := range deques { deques[i] = append(d, newval) } @@ -443,3 +442,70 @@ func Tee2(it Iter) (Iter, Iter) { iters := Tee(it, 2) return iters[0], iters[1] } + +// Permutations returns iterator of all permutations of a finite iterator +func Permutations(it Iter, r ...int) chan []interface{} { + c := make(chan []interface{}) + go func() { + pool := List(it) + n := len(pool) + if len(r) == 0 { + r = append(r, n) + } + indices := []int{} + for i := 0; i < n; i++ { + indices = append(indices, i) + } + cycles := []int{} + for i := n; i >= n-r[0]+1; i-- { + cycles = append(cycles, i) + } + + { + tempSlice := []interface{}{} + for _, i := range indices[:r[0]] { + tempSlice = append(tempSlice, pool[i]) + } + c <- tempSlice + } + + if n == 0 { + close(c) + return + } + + for { + var broken bool + for i := r[0] - 1; i >= 0; i-- { + broken = false + cycles[i]-- + if cycles[i] == 0 { + tempIndex := indices[i] + for t := i; t < len(indices)-1; t++ { + indices[t] = indices[t+1] + } + indices[len(indices)-1] = tempIndex + cycles[i] = n - i + } else { + j := cycles[i] + indices[i], indices[len(indices)-j] = indices[len(indices)-j], indices[i] + { + tempSlice := []interface{}{} + for _, t := range indices[:r[0]] { + tempSlice = append(tempSlice, pool[t]) + } + c <- tempSlice + } + broken = true + break + } + + } + if !broken { + close(c) + return + } + } + }() + return c +} diff --git a/itertools_bench_test.go b/itertools_bench_test.go index 39755a5..240c8e4 100644 --- a/itertools_bench_test.go +++ b/itertools_bench_test.go @@ -66,3 +66,12 @@ func BenchmarkNoReduce(b *testing.B) { } } } + +func BenchmarkPermutations(b *testing.B) { + for i := 0; i < b.N; i++ { + input := Int32(1, 2, 3, 4, 5, 6) + for _ = range Permutations(input, 3) { + + } + } +} diff --git a/itertools_test.go b/itertools_test.go index 38150d5..478399d 100644 --- a/itertools_test.go +++ b/itertools_test.go @@ -1,15 +1,15 @@ package itertools import ( - "testing" "reflect" + "testing" ) // Test iterators for element equality. Allow it1 to be longer than it2 func testIter(t *testing.T, it1, it2 Iter) { t.Log("Start") for el1 := range it1 { - if el2, ok := <- it2; !ok { + if el2, ok := <-it2; !ok { t.Error("it2 shorter than it1!", el1) return } else if !reflect.DeepEqual(el1, el2) { @@ -25,7 +25,7 @@ func testIter(t *testing.T, it1, it2 Iter) { func testIterEq(t *testing.T, it1, it2 Iter) { t.Log("Start") for el1 := range it1 { - if el2, ok := <- it2; !ok { + if el2, ok := <-it2; !ok { t.Error("it2 shorter than it1!", el1) return } else if !reflect.DeepEqual(el1, el2) { @@ -34,22 +34,21 @@ func testIterEq(t *testing.T, it1, it2 Iter) { t.Log(el1, el2) } } - if el2, ok := <- it2; ok { + if el2, ok := <-it2; ok { t.Error("it1 shorter than it2!", el2) } t.Log("Stop") } - func TestList(t *testing.T) { - list := List(New(1,2,3)) - if !reflect.DeepEqual(list, []interface{}{1,2,3}) { + list := List(New(1, 2, 3)) + if !reflect.DeepEqual(list, []interface{}{1, 2, 3}) { t.Error("List didn't make a list", list) } } func TestCount(t *testing.T) { - testIter(t, New(1,2,3,4,5,6,7,8,9), Count(1)) + testIter(t, New(1, 2, 3, 4, 5, 6, 7, 8, 9), Count(1)) } func TestCycle(t *testing.T) { @@ -62,47 +61,46 @@ func TestRepeat(t *testing.T) { } func TestChain(t *testing.T) { - testIterEq(t, Int32(1,2,3,4,5,5,4,3,2,1,100), Chain(Int32(1,2,3,4,5), Int32(5,4,3,2,1), Int32(100))) + testIterEq(t, Int32(1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 100), Chain(Int32(1, 2, 3, 4, 5), Int32(5, 4, 3, 2, 1), Int32(100))) } - func TestDropWhile(t *testing.T) { - pred := func (i interface{}) bool { + pred := func(i interface{}) bool { return i.(int) < 10 } - testIter(t, New(10,11,12,13,14,15), DropWhile(pred, Count(0))) + testIter(t, New(10, 11, 12, 13, 14, 15), DropWhile(pred, Count(0))) } func TestTakeWhile(t *testing.T) { - pred := func (i interface{}) bool { + pred := func(i interface{}) bool { return i.(string)[:3] == "abc" } testIterEq(t, New("abcdef", "abcdaj"), TakeWhile(pred, Cycle(New("abcdef", "abcdaj", "ajcde")))) } func TestFilter(t *testing.T) { - pred := func (i interface{}) bool { - return i.(uint64) % 2 == 1 + pred := func(i interface{}) bool { + return i.(uint64)%2 == 1 } - testIterEq(t, Uint64(1,3,5,7,9), Filter(pred, Uint64(1,2,3,4,5,6,7,8,9,10))) - testIterEq(t, Uint64(2,4,6,8,10), FilterFalse(pred, Uint64(1,2,3,4,5,6,7,8,9,10))) + testIterEq(t, Uint64(1, 3, 5, 7, 9), Filter(pred, Uint64(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))) + testIterEq(t, Uint64(2, 4, 6, 8, 10), FilterFalse(pred, Uint64(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))) } func TestSlice(t *testing.T) { - testIter(t, New(5,6,7,8,9,10), Slice(Count(0), 5)) - testIterEq(t, New(2,3,4,5,6,7,8), Slice(Count(0), 2, 9)) - testIterEq(t, New(3,6,9), Slice(Count(0), 3, 11, 3)) + testIter(t, New(5, 6, 7, 8, 9, 10), Slice(Count(0), 5)) + testIterEq(t, New(2, 3, 4, 5, 6, 7, 8), Slice(Count(0), 2, 9)) + testIterEq(t, New(3, 6, 9), Slice(Count(0), 3, 11, 3)) } func TestMap(t *testing.T) { - mapper := func (i interface{}) interface{} { + mapper := func(i interface{}) interface{} { return len(i.(string)) } - testIterEq(t, New(1,2,3,4), Map(mapper, New("a", "ab", "abc", "abcd"))) + testIterEq(t, New(1, 2, 3, 4), Map(mapper, New("a", "ab", "abc", "abcd"))) } func TestMultiMap(t *testing.T) { - multiMapper := func (is ...interface{}) interface{} { + multiMapper := func(is ...interface{}) interface{} { var s float64 for _, i := range is { s += i.(float64) @@ -113,54 +111,75 @@ func TestMultiMap(t *testing.T) { } func TestZip(t *testing.T) { - a, b, c := []interface{}{1,"a"}, []interface{}{2,nil}, []interface{}{3,nil} - test1, test2 := New(a), New(a,b,c) + a, b, c := []interface{}{1, "a"}, []interface{}{2, nil}, []interface{}{3, nil} + test1, test2 := New(a), New(a, b, c) testIterEq(t, test1, Zip(Count(1), New("a"))) testIterEq(t, test2, ZipLongest(Slice(Count(1), 0, 3), New("a"))) } func TestStarmap(t *testing.T) { - multiMapper := func (is ...interface{}) interface{} { + multiMapper := func(is ...interface{}) interface{} { var s int = 1 for _, i := range is { s *= i.(int) } return s } - testIterEq(t, New(10, 20, 30), Starmap(multiMapper, Zip(New(1,2,3), Repeat(10, 3)))) + testIterEq(t, New(10, 20, 30), Starmap(multiMapper, Zip(New(1, 2, 3), Repeat(10, 3)))) } func TestReduce(t *testing.T) { - summer := func (memo interface{}, el interface{}) interface{} { + summer := func(memo interface{}, el interface{}) interface{} { return memo.(float64) + el.(float64) } - if float64(.82) - Reduce(Float64(.1,.2,.3,.22), summer, float64(0)).(float64) > .000001 { + if float64(.82)-Reduce(Float64(.1, .2, .3, .22), summer, float64(0)).(float64) > .000001 { t.Error("Sum Reduce failed") } } func TestTee2(t *testing.T) { - it1, it2 := Tee2(New(5,4,3,2,1)) + it1, it2 := Tee2(New(5, 4, 3, 2, 1)) for i := range it1 { - j := <- it2 + j := <-it2 if i != j { t.Error("Tees are not coming off equal") } } - it1, it2 = Tee2(New(1,2,3,4,5,6)) - testIterEq(t, New(1,2,3,4,5,6), it1) - testIterEq(t, New(1,2,3,4,5,6), it2) + it1, it2 = Tee2(New(1, 2, 3, 4, 5, 6)) + testIterEq(t, New(1, 2, 3, 4, 5, 6), it1) + testIterEq(t, New(1, 2, 3, 4, 5, 6), it2) } func TestTee(t *testing.T) { - its := Tee(New(3,4,5), 3) + its := Tee(New(3, 4, 5), 3) if len(its) != 3 { t.Error("its length wrong") } for _, it := range its { - testIter(t, New(3,4,5), it) + testIter(t, New(3, 4, 5), it) } } +func factorial(n int) int { + product := 1 + for i := 1; i <= n; i++ { + product *= i + } + return product +} + +func TestPermutations(t *testing.T) { + its := Permutations(New(3, 4, 5, 6), 2) + count := 0 + for p := range its { + count += 1 + if count == 12 && (p[0] != 6 || p[1] != 5) { + t.Error("permutations not in lexicographical order") + } + } + if count != 12 { + t.Error("permutations not 4 pick 2") + } +}