Just a commit

This commit is contained in:
2016-08-15 14:08:39 -05:00
parent 0ef5df860d
commit ec4ec16ac2
50 changed files with 1972 additions and 7 deletions

24
go/custom-set/README.md Normal file
View File

@@ -0,0 +1,24 @@
# Custom Set
Create a custom set type.
Sometimes it is necessary to define a custom data structure of some
type, like a set. In this exercise you will define your own set. How it
works internally doesn't matter, as long as it behaves like a set of
unique elements.
To run the tests simply run the command `go test` in the exercise directory.
If the test suite contains benchmarks, you can run these with the `-bench`
flag:
go test -bench .
For more detailed info about the Go track see the [help
page](http://exercism.io/languages/go).
## Submitting Incomplete Problems
It's possible to submit an incomplete solution so you can see how others have completed the exercise.

368
go/custom-set/cases_test.go Normal file
View File

@@ -0,0 +1,368 @@
package stringset
// Source: exercism/x-common
// Commit: 269f498 Merge pull request #48 from soniakeys/custom-set-json
// Test two sets for equality.
var eqCases = []binBoolCase{
{ // order doesn't matter
[]string{"a", "c"},
[]string{"c", "a"},
true,
},
{ // dupicates don't matter
[]string{"a", "a"},
[]string{"a"},
true,
},
{ // empty sets are equal
[]string{},
[]string{},
true,
},
{ // set with single element is equal to itself
[]string{"a"},
[]string{"a"},
true,
},
{ // different sets are not equal
[]string{"a", "b", "c"},
[]string{"c", "d", "e"},
false,
},
{ // empty set is not equal to non-empty set
[]string{},
[]string{"a", "b", "c"},
false,
},
{ // non-empty set is not equal to empty set
[]string{"a", "b", "c"},
[]string{},
false,
},
{ // having most in common is not good enough
[]string{"a", "b", "c", "d"},
[]string{"b", "c", "d", "e"},
false,
},
}
// Add an element to a set.
var addCases = []eleOpCase{
{ // add to empty set
[]string{},
"c",
[]string{"c"},
},
{ // add to non-empty set
[]string{"a", "b", "d"},
"c",
[]string{"a", "b", "c", "d"},
},
{ // add existing element
[]string{"a", "b", "c"},
"c",
[]string{"a", "b", "c"},
},
}
// Delete an element from a set.
var delCases = []eleOpCase{
{ // delete an element
[]string{"c", "b", "a"},
"b",
[]string{"a", "c"},
},
{ // delete an element not in set
[]string{"c", "b", "a"},
"d",
[]string{"a", "b", "c"},
},
}
// Test if is a set is empty.
var emptyCases = []unaryBoolCase{
{ // empty
[]string{},
true,
},
{ // single element
[]string{"a"},
false,
},
{ // a few elements
[]string{"a", "b", "c", "b"},
false,
},
}
// Return the cardinality of a set.
var lenCases = []unaryIntCase{
{ // empty set
[]string{},
0,
},
{ // non-empty set
[]string{"a", "b", "c"},
3,
},
{ // duplicate element
[]string{"a", "b", "c", "b"},
3,
},
}
// Test if a value is an element of a set.
var hasCases = []eleBoolCase{
{ // nothing is an element of the empty set
[]string{},
"a",
false,
},
{ // 1 is in the set
[]string{"a", "b", "c", "b"},
"a",
true,
},
{ // 2 is in the set
[]string{"a", "b", "c", "b"},
"b",
true,
},
{ // 3 is in the set
[]string{"a", "b", "c", "b"},
"c",
true,
},
{ // 4 not in the set
[]string{"a", "b", "c", "b"},
"d",
false,
},
}
// Test if set1 is a subset of set2.
var subsetCases = []binBoolCase{
{ // empty set is subset of itself
[]string{},
[]string{},
true,
},
{ // empty set is subset of non-empty set
[]string{},
[]string{"a"},
true,
},
{ // non-empty set is not subset of empty set
[]string{"a"},
[]string{},
false,
},
{ // non-empty set is subset of itself
[]string{"a", "b", "c"},
[]string{"a", "b", "c"},
true,
},
{ // proper subset
[]string{"a", "b", "c"},
[]string{"d", "a", "b", "c"},
true,
},
{ // same number of elements
[]string{"a", "b", "c"},
[]string{"d", "a", "c"},
false,
},
{ // superset
[]string{"a", "b", "c", "d", "e"},
[]string{"b", "c", "d"},
false,
},
{ // fewer elements but not a subset
[]string{"a", "b", "c", "k"},
[]string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"},
false,
},
}
// Test if two sets are disjoint.
var disjointCases = []binBoolCase{
{ // the empty set is disjoint with itself
[]string{},
[]string{},
true,
},
{ // empty set disjoint with non-empty set
[]string{},
[]string{"a"},
true,
},
{ // non-empty set disjoint with empty set
[]string{"a"},
[]string{},
true,
},
{ // one element in common
[]string{"a", "b"},
[]string{"b", "c"},
false,
},
{ // no elements in common
[]string{"a", "b"},
[]string{"c", "d"},
true,
},
}
// Produce the union of two sets.
var unionCases = []binOpCase{
{ // union of empty sets
[]string{},
[]string{},
[]string{},
},
{ // union of empty set with set of one element
[]string{},
[]string{"b"},
[]string{"b"},
},
{ // union of empty set with non-empty set
[]string{},
[]string{"c", "b", "e"},
[]string{"b", "c", "e"},
},
{ // union of non-empty set with empty set
[]string{"a", "c"},
[]string{},
[]string{"a", "c"},
},
{ // union of a set with itself
[]string{"a", "c"},
[]string{"c", "a"},
[]string{"a", "c"},
},
{ // union with one element
[]string{"a", "c"},
[]string{"b"},
[]string{"a", "b", "c"},
},
{ // one element in common, one different
[]string{"a", "c"},
[]string{"b", "c"},
[]string{"c", "b", "a"},
},
{ // two elements in common
[]string{"a", "b", "c", "d"},
[]string{"c", "b", "e"},
[]string{"a", "b", "c", "d", "e"},
},
}
// Intersect two sets.
var intersectionCases = []binOpCase{
{ // intersect empty sets
[]string{},
[]string{},
[]string{},
},
{ // intersect empty set with non-empty set
[]string{},
[]string{"c", "b", "e"},
[]string{},
},
{ // intersect non-empty set with empty set
[]string{"a", "b", "c", "d"},
[]string{},
[]string{},
},
{ // intersect one element with itself
[]string{"c"},
[]string{"c"},
[]string{"c"},
},
{ // one element in common, extra elements in both sets
[]string{"a", "b", "c"},
[]string{"c", "e", "d"},
[]string{"c"},
},
{ // two elements in common, extras in both sets
[]string{"a", "b", "c", "d"},
[]string{"c", "b", "e"},
[]string{"b", "c"},
},
{ // intersect with subset
[]string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"},
[]string{"e", "f", "g", "h", "i", "j"},
[]string{"e", "f", "g", "h", "i", "j"},
},
{ // nothing in common
[]string{"a", "b", "c"},
[]string{"d", "e", "f"},
[]string{},
},
}
// Produce the set difference (set1 - set2)
// or more specifically, (set1 set2)
var differenceCases = []binOpCase{
{ // difference of two empty sets
[]string{},
[]string{},
[]string{},
},
{ // difference of empty set and non-empty set
[]string{},
[]string{"c", "b", "e"},
[]string{},
},
{ // difference of non-empty set and empty set
[]string{"a", "b", "c", "d"},
[]string{},
[]string{"a", "b", "c", "d"},
},
{ // no elements in common
[]string{"a", "b", "c"},
[]string{"d"},
[]string{"a", "b", "c"},
},
{ // one element in common, one extra
[]string{"c", "b", "a"},
[]string{"b", "d"},
[]string{"a", "c"},
},
{ // two elements in common, one extra
[]string{"a", "b", "c", "d"},
[]string{"c", "b", "e"},
[]string{"a", "d"},
},
}
// Produce the symmetric difference of two sets. The symmetric
// difference consists of elements in one or the other but not both.
var symmetricDifferenceCases = []binOpCase{
{ // two empty sets
[]string{},
[]string{},
[]string{},
},
{ // empty set and non-empty set
[]string{},
[]string{"c", "b", "e"},
[]string{"c", "b", "e"},
},
{ // non-empty set and empty set
[]string{"a", "b", "c", "d"},
[]string{},
[]string{"a", "b", "c", "d"},
},
{ // no elements in common
[]string{"a", "b", "c"},
[]string{"d"},
[]string{"a", "b", "c", "d"},
},
{ // one element in common
[]string{"c", "b", "a"},
[]string{"b", "d"},
[]string{"a", "c", "d"},
},
}

BIN
go/custom-set/cmd/cmd Executable file

Binary file not shown.

49
go/custom-set/cmd/main.go Normal file
View File

@@ -0,0 +1,49 @@
package main
import (
"fmt"
"../../custom-set"
)
func main() {
fmt.Println("Creating Set 1")
s1 := stringset.NewFromSlice([]string{"a", "b"})
addAndOutput(s1, "A")
addAndOutput(s1, "c")
addAndOutput(s1, "B")
addAndOutput(s1, "B1")
addAndOutput(s1, "A1")
addAndOutput(s1, "B2")
addAndOutput(s1, "A2")
addAndOutput(s1, "B3")
addAndOutput(s1, "A3")
delAndOutput(s1, "a")
fmt.Println("Creating Set 2")
s2 := stringset.NewFromSlice([]string{"A", "c"})
addAndOutput(s2, "a")
addAndOutput(s2, "b")
addAndOutput(s2, "B1")
addAndOutput(s2, "A3")
addAndOutput(s2, "A2")
addAndOutput(s2, "B2")
addAndOutput(s2, "A1")
addAndOutput(s2, "B3")
addAndOutput(s2, "B")
s2.PrettyPrint()
delAndOutput(s2, "a")
s2.PrettyPrint()
}
func addAndOutput(s *stringset.Set, val string) {
fmt.Println("Adding " + val)
s.Add(val)
fmt.Println(s.String())
}
func delAndOutput(s *stringset.Set, val string) {
fmt.Println("Deleting " + val)
s.Delete(val)
fmt.Println(s.String())
}

View File

@@ -0,0 +1,268 @@
package stringset
// Implement Set as a collection of unique string values.
//
// API:
//
// New() Set
// NewFromSlice([]string) Set
// (s Set) Add(string) // modify s
// (s Set) Delete(string) // modify s
// (s Set) Has(string) bool
// (s Set) IsEmpty() bool
// (s Set) Len() int
// (s Set) Slice() []string
// (s Set) String() string
// Equal(s1, s2 Set) bool
// Subset(s1, s2 Set) bool // return s1 ⊆ s2
// Disjoint(s1, s2 Set) bool
// Intersection(s1, s2 Set) Set
// Union(s1, s2 Set) Set
// Difference(s1, s2 Set) Set // return s1 s2
// SymmetricDifference(s1, s2 Set) Set
//
// For Set.String, use '{' and '}', output elements as double-quoted strings
// safely escaped with Go syntax, and use a comma and a single space between
// elements. For example {"a", "b"}.
// Format the empty set as {}.
import (
"math/rand"
"reflect"
"strconv"
"testing"
)
const targetTestVersion = 3
func TestTestVersion(t *testing.T) {
if testVersion != targetTestVersion {
t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion)
}
}
// A first set of tests uses Set.String() to judge correctness.
func TestNew(t *testing.T) {
// New must return an empty set.
want := "{}"
if got := New().String(); got != want {
t.Fatalf(`New().String() = %s, want %s.`, got, want)
}
}
func TestNewFromSlice(t *testing.T) {
// nil slice should give empty set
want := "{}"
if got := NewFromSlice(nil).String(); got != want {
t.Fatalf(`NewFromSlice(nil) = %s, want %s.`, got, want)
}
// slice with one element:
want = `{"a"}`
if got := NewFromSlice([]string{"a"}).String(); got != want {
t.Fatalf(`NewFromSlice([]string{"a"}) = %s, want %s.`, got, want)
}
// slice with repeated element:
if got := NewFromSlice([]string{"a", "a"}).String(); got != want {
t.Fatalf(`NewFromSlice([]string{"a", "a"}) = %s, want %s.`, got, want)
}
// slice with two elements:
got := NewFromSlice([]string{"a", "b"}).String()
want1 := `{"a", "b"}`
want2 := `{"b", "a"}`
if got != want1 && got != want2 { // order undefined
t.Fatalf(`NewFromSlice([]string{"a", "b"}) = %s, want %s or (%s).`,
got, want1, want2)
}
}
func TestSlice(t *testing.T) {
// empty set should produce empty slice
s := New()
if l := s.Slice(); len(l) != 0 {
t.Fatalf(`s.Slice() = %q, want []`, l)
}
// one element:
want := []string{"a"}
s = NewFromSlice(want)
got := s.Slice()
if !reflect.DeepEqual(got, want) {
t.Fatalf(`%v Slice = %q, want %q`, s, got, want)
}
// two elements:
w1 := []string{"a", "b"}
w2 := []string{"b", "a"}
s = NewFromSlice(w1)
got = s.Slice()
if !reflect.DeepEqual(got, w1) && !reflect.DeepEqual(got, w2) {
t.Fatalf(`%v Slice = %q, want %q`, s, got, w1)
}
}
// Trusting NewFromSlice now, remaining tests are table driven, taking data
// from cases_test.go and building sets with NewFromSlice.
// test case types used in cases_test.go
type (
// binary function, bool result (Equal, Subset, Disjoint)
binBoolCase struct {
set1 []string
set2 []string
want bool
}
// unary function, bool result (IsEmpty)
unaryBoolCase struct {
set []string
want bool
}
// unary function, int result (Len)
unaryIntCase struct {
set []string
want int
}
// set-element function, bool result (Has)
eleBoolCase struct {
set []string
ele string
want bool
}
// set-element operator (Add, Delete)
eleOpCase struct {
set []string
ele string
want []string
}
// set-set operator (Union, Intersection, Difference, Symmetric-Difference)
binOpCase struct {
set1 []string
set2 []string
want []string
}
)
// helper for testing Equal, Subset, Disjoint
func testBinBool(name string, f func(Set, Set) bool, cases []binBoolCase, t *testing.T) {
for _, tc := range cases {
s1 := NewFromSlice(tc.set1)
s2 := NewFromSlice(tc.set2)
got := f(s1, s2)
if got != tc.want {
t.Fatalf("%s(%v, %v) = %t, want %t", name, s1, s2, got, tc.want)
}
}
}
func TestEqual(t *testing.T) {
testBinBool("Equal", Equal, eqCases, t)
}
// With Equal tested, remaining tests use it to judge correctness.
// helper for testing Add, Delete
func testEleOp(name string, op func(Set, string), cases []eleOpCase, t *testing.T) {
for _, tc := range cases {
s := NewFromSlice(tc.set)
op(s, tc.ele)
want := NewFromSlice(tc.want)
if !Equal(s, want) {
t.Fatalf("%v %s %q = %v, want %v",
NewFromSlice(tc.set), name, tc.ele, s, want)
}
}
}
func TestAdd(t *testing.T) {
testEleOp("Add", Set.Add, addCases, t)
}
func TestDelete(t *testing.T) {
testEleOp("Delete", Set.Delete, delCases, t)
}
func TestHas(t *testing.T) {
for _, tc := range hasCases {
s := NewFromSlice(tc.set)
got := s.Has(tc.ele)
if got != tc.want {
t.Fatalf("%v Has %q = %t, want %t", s, tc.ele, got, tc.want)
}
}
}
func TestIsEmpty(t *testing.T) {
for _, tc := range emptyCases {
s := NewFromSlice(tc.set)
got := s.IsEmpty()
if got != tc.want {
t.Fatalf("%v IsEmpty = %t, want %t", s, got, tc.want)
}
}
}
func TestLen(t *testing.T) {
for _, tc := range lenCases {
s := NewFromSlice(tc.set)
got := s.Len()
if got != tc.want {
t.Fatalf("%v Len = %d, want %d", s, got, tc.want)
}
}
}
func TestSubset(t *testing.T) {
testBinBool("Subset", Subset, subsetCases, t)
}
func TestDisjoint(t *testing.T) {
testBinBool("Disjoint", Disjoint, disjointCases, t)
}
// helper for testing Union, Intersection, Difference, SymmetricDifference
func testBinOp(name string, f func(Set, Set) Set, cases []binOpCase, t *testing.T) {
for _, tc := range cases {
s1 := NewFromSlice(tc.set1)
s2 := NewFromSlice(tc.set2)
want := NewFromSlice(tc.want)
got := f(s1, s2)
if !Equal(got, want) {
t.Fatalf("%s(%v, %v) = %v, want %v", name, s1, s2, got, want)
}
}
}
func TestUnion(t *testing.T) {
testBinOp("Union", Union, unionCases, t)
}
func TestIntersection(t *testing.T) {
testBinOp("Intersection", Intersection, intersectionCases, t)
}
func TestDifference(t *testing.T) {
testBinOp("Difference", Difference, differenceCases, t)
}
func TestSymmetricDifference(t *testing.T) {
testBinOp("SymmetricDifference", SymmetricDifference, symmetricDifferenceCases, t)
}
func BenchmarkNewFromSlice1e1(b *testing.B) { bench(1e1, b) }
func BenchmarkNewFromSlice1e2(b *testing.B) { bench(1e2, b) }
func BenchmarkNewFromSlice1e3(b *testing.B) { bench(1e3, b) }
func BenchmarkNewFromSlice1e4(b *testing.B) { bench(1e4, b) }
func bench(nAdd int, b *testing.B) {
s := make([]string, nAdd)
for i := range s {
s[i] = strconv.Itoa(rand.Intn(len(s)))
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
NewFromSlice(s)
}
}

388
go/custom-set/stringset.go Normal file
View File

@@ -0,0 +1,388 @@
package stringset
import (
"errors"
"fmt"
"strings"
)
const testVersion = 3
// Set is a slice of strings that you can do set operations on.
// I decided that I wanted to implement a binary tree for the storage
type Set struct {
top SetValue
}
type SetValue struct {
value string
left *SetValue
right *SetValue
}
// New returns an empty Set
func New() Set {
s := new(Set)
s.top = SetValue{}
return *s
}
// NewFromSlice takes a slice of strings and returns a Set
func NewFromSlice(s []string) Set {
ret := New()
for i := range s {
ret.Add(s[i])
}
ret.balance()
return ret
}
// Add adds a value to the set
func (s Set) Add(v string) {
if s.top.value == "" {
s.top.value = v
return
}
s.top.Add(v)
}
func (s *Set) PrettyPrint() {
s.pp(&s.top, 0)
}
func (s *Set) pp(n *SetValue, indent int) {
if n != nil {
if n.left != nil {
s.pp(n.left, indent+4)
}
if n.right != nil {
s.pp(n.right, indent+4)
}
for ; indent > 0; indent-- {
fmt.Print(" ")
}
fmt.Println(n.value)
}
}
// balance balances the binary tree
func (s *Set) balance() {
}
func (s *Set) find(v string) *SetValue {
if s.top.value != "" {
sv, _ := s.top.find(v)
return sv
}
return nil
}
// findWithParent finds a node with a child value v
// a return of nil, nil means it's the top node
func (s *Set) findParent(v string) (*SetValue, error) {
if s.top.value == v {
// no parent, it's the top.
return nil, nil
} else {
return s.top.findParent(v)
}
return nil, errors.New("Empty Set")
}
func (s *Set) findHome(v *SetValue) {
if s.top.value == "" {
s.top.value = v.value
s.top.left = v.left
s.top.right = v.right
return
}
s.top.findHome(v)
}
// Delete removes the given value from the set
func (s Set) Delete(v string) {
if sv, err := s.findParent(v); err == nil {
var cmp int
var delNode, repNode, orphan *SetValue
if sv == nil {
// Deleting 'top'
delNode = &s.top
if delNode.left != nil {
repNode = delNode.left
orphan = delNode.right
} else if delNode.right != nil {
repNode = delNode.right
}
if repNode == nil {
// No node to replace it with, we're done
return
}
s.top = *repNode
} else {
cmp = strings.Compare(v, sv.value)
if cmp < 0 && sv.left != nil {
fmt.Println(" Left: " + sv.left.value)
// It's the left node
delNode = sv.left
} else if cmp > 0 && sv.right != nil {
fmt.Println(" Right: " + sv.right.value)
// It's the right node
delNode = sv.right
}
if delNode == nil {
return
}
if delNode.left != nil {
repNode = delNode.left
orphan = delNode.right
} else if delNode.right != nil {
repNode = delNode.right
}
if repNode == nil {
// No replacement node, we're done
return
}
if cmp < 0 {
sv.left = repNode
} else if cmp > 0 {
sv.right = repNode
}
}
// If we have an orphaned branch, find it a home
if orphan != nil {
s.findHome(orphan)
}
}
}
// Has returns if the set contains the given value.
func (s *Set) Has(v string) bool {
return s.find(v) != nil
}
// IsEmpty returns whether the set is empty or not.
func (s *Set) IsEmpty() bool {
return s.top.value == ""
}
// Len returns the number of values in the set
func (s *Set) Len() int {
if !s.IsEmpty() {
return s.top.Len()
}
return 0
}
// Slice returns a string slice of the set
func (s Set) Slice() []string {
if !s.IsEmpty() {
return s.top.Slice()
}
return []string{}
}
// String converts the set to a string
func (s Set) String() string {
ret := "{"
if s.top.value != "" {
ret += s.top.String()
}
ret += "}"
return ret
}
// find looks for a node with value val, it either returns the node
// or an error stating it couldn't find it.
func (sv *SetValue) find(val string) (*SetValue, error) {
if sv.value == val {
return sv, nil
}
cmp := strings.Compare(val, sv.value)
if cmp < 0 && sv.left != nil {
return sv.left.find(val)
}
if cmp > 0 && sv.right != nil {
return sv.right.find(val)
}
return nil, errors.New("Value not found")
}
// findParent looks for the parent of the node with value val
// If nil, nil is returned, it _is_ this node.
func (sv *SetValue) findParent(val string) (*SetValue, error) {
if sv.value == val {
// This should only trigger if this is the top node of the tree
return nil, nil
}
cmp := strings.Compare(val, sv.value)
if cmp < 0 && sv.left != nil {
if sv.left.value == val {
return sv, nil
}
return sv.left.findParent(val)
}
if cmp > 0 && sv.right != nil {
if sv.right.value == val {
return sv, nil
}
return sv.right.findParent(val)
}
return nil, errors.New("Value not found")
}
func (sv *SetValue) findHome(v *SetValue) {
cmp := strings.Compare(v.value, sv.value)
if cmp < 0 {
if sv.left == nil {
sv.left = v
} else {
sv.left.findHome(v)
}
} else if cmp > 0 {
if sv.right == nil {
sv.right = v
} else {
sv.right.findHome(v)
}
} else {
// Discard the top node, find homes for it's children
if v.left != nil {
sv.findHome(v.left)
}
if v.right != nil {
sv.findHome(v.right)
}
}
}
func (sv *SetValue) Add(v string) {
cmp := strings.Compare(v, sv.value)
if cmp < 0 {
if sv.left == nil {
sv.left = &SetValue{value: v}
} else {
sv.left.Add(v)
}
} else if cmp > 0 {
if sv.right == nil {
sv.right = &SetValue{value: v}
} else {
sv.right.Add(v)
}
}
}
// Len returns how many elements are in the branches
func (sv *SetValue) Len() int {
ret := 1
if sv.left != nil {
ret += sv.left.Len()
}
if sv.right != nil {
ret += sv.right.Len()
}
return ret
}
// Has checks if this branch contains the value v
func (sv *SetValue) Has(v string) bool {
ret, _ := sv.find(v)
return ret != nil
}
// String gets a string value of this branch
func (sv *SetValue) String() string {
var ret string
if sv.left != nil {
ret += sv.left.String() + ", "
}
ret += "\"" + sv.value + "\""
if sv.right != nil {
ret += ", " + sv.right.String()
}
return ret
}
// Slice returns a string slice of all values in the branch
func (sv *SetValue) Slice() []string {
var ret []string
if sv.left != nil {
ret = sv.left.Slice()
}
ret = append(ret, sv.value)
if sv.right != nil {
ret = append(ret, sv.right.Slice()...)
}
return ret
}
// Equal returns whether the given sets are the same.
func Equal(s1, s2 Set) bool {
return s1.String() == s2.String()
}
// Subset returns whether s1 is a subset of s2.
func Subset(s1, s2 Set) bool {
if s1.Len() == 0 || s2.Len() == 0 {
return false
}
s1Sl := s1.Slice()
for i := range s1Sl {
if !s2.Has(s1Sl[i]) {
return false
}
}
return true
}
// Disjoint returns whether two sets _do not_ intersect
func Disjoint(s1, s2 Set) bool {
s1Sl := s1.Slice()
for i := range s1Sl {
if s2.Has(s1Sl[i]) {
return false
}
}
return false
}
// Intersection finds elements that exist in both sets and makes a new
// set of them
func Intersection(s1, s2 Set) Set {
var vals []string
s1Sl := s1.Slice()
for i := range s1Sl {
if s2.Has(s1Sl[i]) {
vals = append(vals, s1Sl[i])
}
}
return NewFromSlice(vals)
}
// Union gets all elements in both sets and makes a new set with them.
func Union(s1, s2 Set) Set {
var vals []string
vals = append(vals, s1.Slice()...)
vals = append(vals, s2.Slice()...)
return NewFromSlice(vals)
}
// Difference returns a Set of all elements in s1 that aren't in s2
func Difference(s1, s2 Set) Set {
var vals []string
s1Sl := s1.Slice()
for i := range s1Sl {
if !s2.Has(s1Sl[i]) {
vals = append(vals, s1Sl[i])
}
}
return NewFromSlice(vals)
}
// SymmetricDifference returns all elements from s1 & s2 that occur in only one of the
// sets.
func SymmetricDifference(s1, s2 Set) Set {
return Union(Difference(s1, s2), Difference(s2, s1))
}