Skip to content

Commit

Permalink
Merge pull request #10 from tideland/4-add-unique-functions
Browse files Browse the repository at this point in the history
Add functions to unify elements
  • Loading branch information
themue authored Aug 17, 2022
2 parents 3e5b79e + e772f8b commit 4482d2e
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 1 deletion.
36 changes: 36 additions & 0 deletions slices.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,4 +257,40 @@ func TakeWhile[V any](pred func(V) bool, ivs []V) []V {
return Subslice(ivs, 0, taken)
}

// Unique returns a slice which contains each value only once. The second
// and further values are deleted.
func Unique[V comparable](ivs []V) []V {
if ivs == nil {
return nil
}
var ovs []V = []V{}
var isContained map[V]struct{} = map[V]struct{}{}
for _, v := range ivs {
if _, ok := isContained[v]; !ok {
ovs = append(ovs, v)
isContained[v] = struct{}{}
}
}
return ovs
}

// UniqueWith returns a slice which contains each pred returned value only once.
// The second and further values are deleted. The returned value could be a
// e.g. field of a struct.
func UniqueWith[V any, C comparable](pred func(V) C, ivs []V) []V {
if ivs == nil {
return nil
}
var ovs []V = []V{}
var isContained map[C]struct{} = map[C]struct{}{}
for _, v := range ivs {
cv := pred(v)
if _, ok := isContained[cv]; !ok {
ovs = append(ovs, v)
isContained[cv] = struct{}{}
}
}
return ovs
}

// EOF
109 changes: 108 additions & 1 deletion slices_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,7 @@ func TestSubsclice(t *testing.T) {
}
}

// TestSubtract ...
// TestSubtract verifies the subtracting of values froma a slice.
func TestSubtract(t *testing.T) {
assert := asserts.NewTesting(t, asserts.FailStop)

Expand Down Expand Up @@ -831,4 +831,111 @@ func TestTakeWhile(t *testing.T) {
}
}

// TestUnique verifies the unifying of a slice.
func TestUnique(t *testing.T) {
assert := asserts.NewTesting(t, asserts.FailStop)

tests := []struct {
descr string
values []int
out []int
}{
{
descr: "Longer slice with one double value",
values: []int{1, 2, 3, 4, 5, 6, 5, 7, 8, 9},
out: []int{1, 2, 3, 4, 5, 6, 7, 8, 9},
}, {
descr: "Longer slice with one multiple time value",
values: []int{1, 2, 5, 3, 5, 4, 5, 6, 5, 7, 8, 9},
out: []int{1, 2, 5, 3, 4, 6, 7, 8, 9},
}, {
descr: "Longer slice with multiple multiple time values",
values: []int{1, 2, 5, 3, 4, 5, 4, 5, 6, 6, 5, 7, 7, 8, 7, 9},
out: []int{1, 2, 5, 3, 4, 6, 7, 8, 9},
}, {
descr: "Longer slice without any double value",
values: []int{1, 2, 3, 4, 5, 6, 7, 8, 9},
out: []int{1, 2, 3, 4, 5, 6, 7, 8, 9},
}, {
descr: "Longer slice only with double values",
values: []int{1, 1, 1, 1, 1, 1, 1, 1, 1},
out: []int{1},
}, {
descr: "Single value slice",
values: []int{0},
out: []int{0},
}, {
descr: "Empty slice",
values: []int{},
out: []int{},
}, {
descr: "Nil slice",
values: nil,
out: nil,
},
}

for _, test := range tests {
assert.Logf(test.descr)
assert.Equal(slices.Unique(test.values), test.out)
}
}

// TestUnique verifies the unifying of a slice.
func TestUniqueWith(t *testing.T) {
assert := asserts.NewTesting(t, asserts.FailStop)

type foo struct {
key string
value int
}
fookey := func(f foo) string { return f.key }

tests := []struct {
descr string
values []foo
out []foo
}{
{
descr: "Longer slice with one double value",
values: []foo{{"one", 1}, {"two", 2}, {"three", 3}, {"four", 4}, {"three", 3}},
out: []foo{{"one", 1}, {"two", 2}, {"three", 3}, {"four", 4}},
}, {
descr: "Longer slice with one multiple time value",
values: []foo{{"one", 1}, {"two", 2}, {"three", 3}, {"four", 4}, {"three", 3}, {"three", 3}},
out: []foo{{"one", 1}, {"two", 2}, {"three", 3}, {"four", 4}},
}, {
descr: "Longer slice with multiple multiple time values",
values: []foo{{"one", 1}, {"two", 2}, {"three", 3}, {"four", 4}, {"three", 3}, {"three", 3},
{"two", 2}, {"three", 3}, {"four", 4}, {"one", 1}},
out: []foo{{"one", 1}, {"two", 2}, {"three", 3}, {"four", 4}},
}, {
descr: "Longer slice without any double values",
values: []foo{{"one", 1}, {"two", 2}, {"three", 3}, {"four", 4}, {"five", 5}},
out: []foo{{"one", 1}, {"two", 2}, {"three", 3}, {"four", 4}, {"five", 5}},
}, {
descr: "Longer slice ony with double values/keys",
values: []foo{{"one", 1}, {"one", 2}, {"one", 3}, {"one", 4}, {"one", 5}},
out: []foo{{"one", 1}},
}, {
descr: "Single value slice",
values: []foo{{"one", 1}},
out: []foo{{"one", 1}},
}, {
descr: "Empty slice",
values: []foo{},
out: []foo{},
}, {
descr: "Nil slice",
values: nil,
out: nil,
},
}

for _, test := range tests {
assert.Logf(test.descr)
assert.Equal(slices.UniqueWith(fookey, test.values), test.out)
}
}

// EOF

0 comments on commit 4482d2e

Please sign in to comment.