-
-
Notifications
You must be signed in to change notification settings - Fork 20
/
combinations.go
88 lines (74 loc) · 2.38 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
// Package combinations provides a method to generate all combinations out of a given generic array.
package combinations
import "math/bits"
// All returns all combinations for a given generic array.
// This is essentially a powerset of the given set except that the empty set is disregarded.
func All[T any](set []T) (subsets [][]T) {
length := uint(len(set))
// Go through all possible combinations of objects
// from 1 (only first object in subset) to 2^length (all objects in subset)
for subsetBits := 1; subsetBits < (1 << length); subsetBits++ {
var subset []T
for object := uint(0); object < length; object++ {
// checks if object is contained in subset
// by checking if bit 'object' is set in subsetBits
if (subsetBits>>object)&1 == 1 {
// add object to subset
subset = append(subset, set[object])
}
}
// add subset to subsets
subsets = append(subsets, subset)
}
return subsets
}
// AllRepeat returns all combinations with repetitions for a given slice,
// from 1 up to a maximum combination length of m.
func AllRepeat[T any](set []T, m int) (subsets [][]T) {
if m < 1 {
return nil
}
var generateCombos func([]T, int)
generateCombos = func(current []T, depth int) {
if depth == 0 {
subset := make([]T, len(current))
copy(subset, current)
subsets = append(subsets, subset)
return
}
for _, item := range set {
generateCombos(append(current, item), depth-1)
}
}
for length := 1; length <= m; length++ {
generateCombos([]T{}, length)
}
return subsets
}
// Combinations returns combinations of n elements for a given generic array.
// For n < 1, it equals to All and returns all combinations.
func Combinations[T any](set []T, n int) (subsets [][]T) {
length := uint(len(set))
if n > len(set) {
n = len(set)
}
// Go through all possible combinations of objects
// from 1 (only first object in subset) to 2^length (all objects in subset)
for subsetBits := 1; subsetBits < (1 << length); subsetBits++ {
if n > 0 && bits.OnesCount(uint(subsetBits)) != n {
continue
}
var subset []T
for object := uint(0); object < length; object++ {
// checks if object is contained in subset
// by checking if bit 'object' is set in subsetBits
if (subsetBits>>object)&1 == 1 {
// add object to subset
subset = append(subset, set[object])
}
}
// add subset to subsets
subsets = append(subsets, subset)
}
return subsets
}