From 65bd8c99d072f7f61b5304f098001ecc71f82e71 Mon Sep 17 00:00:00 2001 From: Evan Burkey Date: Thu, 3 Nov 2022 07:54:02 -0700 Subject: [PATCH] add PermutationsAllSizes --- go.sum | 2 ++ permutation.go | 49 ++++++++++++++++++++++++++++++++++----------- permutation_test.go | 49 ++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 83 insertions(+), 17 deletions(-) create mode 100644 go.sum diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..9aac26a --- /dev/null +++ b/go.sum @@ -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= diff --git a/permutation.go b/permutation.go index 6fb9ea8..be6f6d2 100644 --- a/permutation.go +++ b/permutation.go @@ -4,28 +4,24 @@ lists. It uses Go 1.18's new generics feature to provide a generic interface */ 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 of the provided list. Most slices will automatically coerce -their type into a GenSlice[T] with no casting required +permutations of the provided list. */ -func Permutations[T any](arr GenSlice[T]) []GenSlice[T] { - var helper func(GenSlice[T], int) - var res []GenSlice[T] +func Permutations[T comparable](arr []T) [][]T { + var heapsAlgo func([]T, int) + var res [][]T - helper = func(arr GenSlice[T], n int) { + heapsAlgo = func(arr []T, n int) { if n == 1 { - var tmp GenSlice[T] + var tmp []T for _, i := range arr { tmp = append(tmp, i) } res = append(res, tmp) } else { for i := 0; i < n; i++ { - helper(arr, n-1) + heapsAlgo(arr, n-1) if n%2 == 1 { tmp := arr[i] 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 } + +/* +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 +} diff --git a/permutation_test.go b/permutation_test.go index 7bb94ec..98e1877 100644 --- a/permutation_test.go +++ b/permutation_test.go @@ -1,12 +1,51 @@ package permutation import ( - "fmt" "testing" ) -func Test(t *testing.T) { - a := []int{1, 2, 3, 4} - p := Permutations(a) - fmt.Println(p) +func TestPermutations(t *testing.T) { + testCases := []struct { + name string + 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) + } + }) + } }