-
Notifications
You must be signed in to change notification settings - Fork 0
/
combinations.go
129 lines (102 loc) · 2.53 KB
/
combinations.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package combinatoric
import (
"errors"
"math/big"
)
// CombinationIterator implements an Iterator to generate unique
// combinations of a given slice.
//
// CombinationIterator is not threadsafe, and should always be
// initialized through Combinations. Return values from First and Next
// share the same memory address. Use copy if the value must persist
// between iterations.
type CombinationIterator struct {
pool []interface{}
n int
r int
indices []int
max uint64
iters uint64
res []interface{}
}
// First resets the iterator to its starting state and returns the first
// combination.
func (iter *CombinationIterator) First() []interface{} {
iter.Reset()
return iter.Next()
}
// Next returns the next value in the iterator or returns nil.
func (iter *CombinationIterator) Next() []interface{} {
if !iter.HasNext() {
return nil
}
if iter.res[0] != nil {
i := iter.r - 1
for ; i > -1; i-- {
if iter.indices[i] != i+iter.n-iter.r {
break
}
}
if i > -1 {
iter.indices[i] += 1
for j := i + 1; j < iter.r; j++ {
iter.indices[j] = iter.indices[j-1] + 1
}
}
}
for j := 0; j < iter.r; j++ {
iter.res[j] = iter.pool[iter.indices[j]]
}
iter.iters += 1
return iter.res
}
// HasNext returns true if the iterator is not yet exhausted.
func (iter *CombinationIterator) HasNext() bool {
return iter.iters < iter.max
}
// Reset returns the iterator to its starting state.
func (iter *CombinationIterator) Reset() {
iter.iters = 0
iter.indices = make([]int, iter.r)
for i := 0; i < iter.r; i++ {
iter.indices[i] = i
}
iter.res = make([]interface{}, iter.r, iter.r)
}
// Len returns the maximum iterations.
func (iter *CombinationIterator) Len() uint64 {
return iter.max
}
func lenCombinations(n int, r int) uint64 {
n64 := int64(n)
r64 := int64(r)
if n < r {
return 0
}
total := big.NewInt(0)
total.Mul(
factorial(big.NewInt(n64-r64)),
factorial(big.NewInt(r64)),
)
total.Div(factorial(big.NewInt(n64)), total)
return total.Uint64()
}
// Combinations creates a new CombinationIterator for a given slice and
// desired output size.
func Combinations(pool []interface{}, r int) (*CombinationIterator, error) {
n := len(pool)
if r > n {
return nil, errors.New("Result size is larger than input")
}
iter := &CombinationIterator{
pool: pool,
n: n,
r: r,
res: make([]interface{}, r, r),
max: lenCombinations(n, r),
}
iter.Reset()
return iter, nil
}
// Type casting to insure CombinationIterator implements Iterator.
var _ Iterator = (*CombinationIterator)(nil)