add PermutationsAllSizes

This commit is contained in:
Evan Burkey 2022-11-03 07:54:02 -07:00
parent 61655a2799
commit 65bd8c99d0
3 changed files with 83 additions and 17 deletions

2
go.sum Normal file
View File

@ -0,0 +1,2 @@
golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 h1:QfTh0HpN6hlw6D3vu8DAwC8pBIwikq0AI1evdm+FksE=
golang.org/x/exp v0.0.0-20221031165847-c99f073a8326/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=

View File

@ -4,28 +4,24 @@ lists. It uses Go 1.18's new generics feature to provide a generic interface
*/ */
package permutation package permutation
// GenSlice is a generic slice of data
type GenSlice[T any] []T
/* /*
Permutations uses Heap's Algorithm to generate a list of all possible Permutations uses Heap's Algorithm to generate a list of all possible
permutations of the provided list. Most slices will automatically coerce permutations of the provided list.
their type into a GenSlice[T] with no casting required
*/ */
func Permutations[T any](arr GenSlice[T]) []GenSlice[T] { func Permutations[T comparable](arr []T) [][]T {
var helper func(GenSlice[T], int) var heapsAlgo func([]T, int)
var res []GenSlice[T] var res [][]T
helper = func(arr GenSlice[T], n int) { heapsAlgo = func(arr []T, n int) {
if n == 1 { if n == 1 {
var tmp GenSlice[T] var tmp []T
for _, i := range arr { for _, i := range arr {
tmp = append(tmp, i) tmp = append(tmp, i)
} }
res = append(res, tmp) res = append(res, tmp)
} else { } else {
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
helper(arr, n-1) heapsAlgo(arr, n-1)
if n%2 == 1 { if n%2 == 1 {
tmp := arr[i] tmp := arr[i]
arr[i] = arr[n-1] arr[i] = arr[n-1]
@ -38,6 +34,35 @@ func Permutations[T any](arr GenSlice[T]) []GenSlice[T] {
} }
} }
} }
helper(arr, len(arr)) heapsAlgo(arr, len(arr))
return res return res
} }
/*
PermutationsAllSizes returns all permutations of every possible combination in a slice.
This includes single item sets.
*/
func PermutationsAllSizes[T comparable](arr []T) (result [][]T) {
sets := generateSets(arr)
for _, set := range sets {
perms := Permutations(set)
for _, perm := range perms {
result = append(result, perm)
}
}
return result
}
func generateSets[T comparable](arr []T) (result [][]T) {
l := uint(len(arr))
for b := 1; b < (1 << l); b++ {
var s []T
for i := uint(0); i < l; i++ {
if (b>>i)&1 == 1 {
s = append(s, arr[i])
}
}
result = append(result, s)
}
return result
}

View File

@ -1,12 +1,51 @@
package permutation package permutation
import ( import (
"fmt"
"testing" "testing"
) )
func Test(t *testing.T) { func TestPermutations(t *testing.T) {
a := []int{1, 2, 3, 4} testCases := []struct {
p := Permutations(a) name string
fmt.Println(p) seed []int
permsExpected int
}{
{
"basic",
[]int{1, 2, 3},
6,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
perms := Permutations(testCase.seed)
if len(perms) != testCase.permsExpected {
t.Errorf("len(perms) == %d, expected %d", len(perms), testCase.permsExpected)
}
})
}
}
func TestPermutationsAllSizes(t *testing.T) {
testCases := []struct {
name string
seed []int
permsExpected int
}{
{
"3 ints",
[]int{1, 2, 3},
15,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
perms := PermutationsAllSizes(testCase.seed)
if len(perms) != testCase.permsExpected {
t.Errorf("len(perms) == %d, expected %d", len(perms), testCase.permsExpected)
}
})
}
} }