From e6f6469327e8a7693e9b029eca900c1e64134578 Mon Sep 17 00:00:00 2001 From: Cooper Tseng Date: Thu, 27 Jun 2024 15:19:28 +0800 Subject: [PATCH] Add SliceFindDuplicates function --- slice.go | 20 ++++++++++++++++++++ slice_test.go | 10 ++++++++++ 2 files changed, 30 insertions(+) diff --git a/slice.go b/slice.go index 7129203..9efebda 100644 --- a/slice.go +++ b/slice.go @@ -54,3 +54,23 @@ func SliceMapFunc[S ~[]E, E any](s S, f func(E, int) E) S { } return r } + +// SliceFindDuplicates takes a slice of comparable elements and returns a new slice containing +// only the elements that appear more than once in the input slice. Since a map is used +// internally to track duplicates, the order of the elements in the output slice is not guaranteed. +func SliceFindDuplicates[S ~[]E, E comparable](s S) S { + elementCount := make(map[E]int) + duplicates := []E{} + + for _, element := range s { + elementCount[element]++ + } + + for element, count := range elementCount { + if count > 1 { + duplicates = append(duplicates, element) + } + } + + return duplicates +} diff --git a/slice_test.go b/slice_test.go index 0ff483c..8f6976f 100644 --- a/slice_test.go +++ b/slice_test.go @@ -90,3 +90,13 @@ func (s *SliceFuncs) TestSliceMapFunc() { return strings.TrimSpace(v) }), "SliceMapFunc should return {\"a\", \"b\", \"c\"}") } + +func (s *SliceFuncs) TestSliceFindDuplicates() { + a := []string{"foo", "bar", "bar", "foo", "roll", "roll"} + b := []string{"apple", "book", "clock", "duck", "escape", "field"} + c := []string{"foo", "bar", "roll", "roll", "desk"} + + require.ElementsMatch(s.T(), []string{"foo", "bar", "roll"}, SliceFindDuplicates(a), "SliceFindDuplicates should return elements: {foo, bar, roll}") + require.ElementsMatch(s.T(), []string{}, SliceFindDuplicates(b), "SliceFindDuplicates should return elements: {}") + require.ElementsMatch(s.T(), []string{"roll"}, SliceFindDuplicates(c), "SliceFindDuplicates should return elements: {roll}") +}