diff options
-rw-r--r-- | src/maps/example_test.go | 45 | ||||
-rw-r--r-- | src/slices/example_test.go | 322 | ||||
-rw-r--r-- | src/slices/slices.go | 11 | ||||
-rw-r--r-- | src/slices/sort.go | 4 |
4 files changed, 374 insertions, 8 deletions
diff --git a/src/maps/example_test.go b/src/maps/example_test.go new file mode 100644 index 0000000000..779c66dcef --- /dev/null +++ b/src/maps/example_test.go @@ -0,0 +1,45 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package maps_test + +import ( + "fmt" + "maps" + "strings" +) + +func ExampleDeleteFunc() { + m := map[string]int{ + "one": 1, + "two": 2, + "three": 3, + "four": 4, + } + maps.DeleteFunc(m, func(k string, v int) bool { + return v%2 != 0 // delete odd values + }) + fmt.Println(m) + // Output: + // map[four:4 two:2] +} + +func ExampleEqualFunc() { + m1 := map[int]string{ + 1: "one", + 10: "Ten", + 1000: "THOUSAND", + } + m2 := map[int][]byte{ + 1: []byte("One"), + 10: []byte("Ten"), + 1000: []byte("Thousand"), + } + eq := maps.EqualFunc(m1, m2, func(v1 string, v2 []byte) bool { + return strings.ToLower(v1) == strings.ToLower(string(v2)) + }) + fmt.Println(eq) + // Output: + // true +} diff --git a/src/slices/example_test.go b/src/slices/example_test.go new file mode 100644 index 0000000000..3e76907bb7 --- /dev/null +++ b/src/slices/example_test.go @@ -0,0 +1,322 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package slices_test + +import ( + "cmp" + "fmt" + "slices" + "strconv" + "strings" +) + +func ExampleBinarySearch() { + names := []string{"Alice", "Bob", "Vera"} + n, found := slices.BinarySearch(names, "Vera") + fmt.Println("Vera:", n, found) + n, found = slices.BinarySearch(names, "Bill") + fmt.Println("Bill:", n, found) + // Output: + // Vera: 2 true + // Bill: 1 false +} + +func ExampleBinarySearchFunc() { + type Person struct { + Name string + Age int + } + people := []Person{ + {"Alice", 55}, + {"Bob", 24}, + {"Gopher", 13}, + } + n, found := slices.BinarySearchFunc(people, Person{"Bob", 0}, func(a, b Person) int { + return cmp.Compare(a.Name, b.Name) + }) + fmt.Println("Bob:", n, found) + // Output: + // Bob: 1 true +} + +func ExampleCompact() { + seq := []int{0, 1, 1, 2, 3, 5, 8} + seq = slices.Compact(seq) + fmt.Println(seq) + // Output: + // [0 1 2 3 5 8] +} + +func ExampleCompactFunc() { + names := []string{"bob", "Bob", "alice", "Vera", "VERA"} + names = slices.CompactFunc(names, func(a, b string) bool { + return strings.ToLower(a) == strings.ToLower(b) + }) + fmt.Println(names) + // Output: + // [bob alice Vera] +} + +func ExampleCompare() { + names := []string{"Alice", "Bob", "Vera"} + fmt.Println("Equal:", slices.Compare(names, []string{"Alice", "Bob", "Vera"})) + fmt.Println("V < X:", slices.Compare(names, []string{"Alice", "Bob", "Xena"})) + fmt.Println("V > C:", slices.Compare(names, []string{"Alice", "Bob", "Cat"})) + fmt.Println("3 > 2:", slices.Compare(names, []string{"Alice", "Bob"})) + // Output: + // Equal: 0 + // V < X: -1 + // V > C: 1 + // 3 > 2: 1 +} + +func ExampleCompareFunc() { + numbers := []int{0, 43, 8} + strings := []string{"0", "0", "8"} + result := slices.CompareFunc(numbers, strings, func(n int, s string) int { + sn, err := strconv.Atoi(s) + if err != nil { + return 1 + } + return cmp.Compare(n, sn) + }) + fmt.Println(result) + // Output: + // 1 +} + +func ExampleContainsFunc() { + numbers := []int{0, 42, -10, 8} + hasNegative := slices.ContainsFunc(numbers, func(n int) bool { + return n < 0 + }) + fmt.Println("Has a negative:", hasNegative) + hasOdd := slices.ContainsFunc(numbers, func(n int) bool { + return n%2 != 0 + }) + fmt.Println("Has an odd number:", hasOdd) + // Output: + // Has a negative: true + // Has an odd number: false +} + +func ExampleDelete() { + letters := []string{"a", "b", "c", "d", "e"} + letters = slices.Delete(letters, 1, 4) + fmt.Println(letters) + // Output: + // [a e] +} + +func ExampleDeleteFunc() { + seq := []int{0, 1, 1, 2, 3, 5, 8} + seq = slices.DeleteFunc(seq, func(n int) bool { + return n%2 != 0 // delete the odd numbers + }) + fmt.Println(seq) + // Output: + // [0 2 8] +} + +func ExampleEqual() { + numbers := []int{0, 42, 8} + fmt.Println(slices.Equal(numbers, []int{0, 42, 8})) + fmt.Println(slices.Equal(numbers, []int{10})) + // Output: + // true + // false +} + +func ExampleEqualFunc() { + numbers := []int{0, 42, 8} + strings := []string{"000", "42", "0o10"} + equal := slices.EqualFunc(numbers, strings, func(n int, s string) bool { + sn, err := strconv.ParseInt(s, 0, 64) + if err != nil { + return false + } + return n == int(sn) + }) + fmt.Println(equal) + // Output: + // true +} + +func ExampleIndex() { + numbers := []int{0, 42, 8} + fmt.Println(slices.Index(numbers, 8)) + fmt.Println(slices.Index(numbers, 7)) + // Output: + // 2 + // -1 +} + +func ExampleIndexFunc() { + numbers := []int{0, 42, -10, 8} + i := slices.IndexFunc(numbers, func(n int) bool { + return n < 0 + }) + fmt.Println("First negative at index", i) + // Output: + // First negative at index 2 +} + +func ExampleInsert() { + names := []string{"Alice", "Bob", "Vera"} + names = slices.Insert(names, 1, "Bill", "Billie") + names = slices.Insert(names, len(names), "Zac") + fmt.Println(names) + // Output: + // [Alice Bill Billie Bob Vera Zac] +} + +func ExampleIsSorted() { + fmt.Println(slices.IsSorted([]string{"Alice", "Bob", "Vera"})) + fmt.Println(slices.IsSorted([]int{0, 2, 1})) + // Output: + // true + // false +} + +func ExampleIsSortedFunc() { + names := []string{"alice", "Bob", "VERA"} + isSortedInsensitive := slices.IsSortedFunc(names, func(a, b string) int { + return cmp.Compare(strings.ToLower(a), strings.ToLower(b)) + }) + fmt.Println(isSortedInsensitive) + fmt.Println(slices.IsSorted(names)) + // Output: + // true + // false +} + +func ExampleMax() { + numbers := []int{0, 42, -10, 8} + fmt.Println(slices.Max(numbers)) + // Output: + // 42 +} + +func ExampleMaxFunc() { + type Person struct { + Name string + Age int + } + people := []Person{ + {"Gopher", 13}, + {"Alice", 55}, + {"Vera", 24}, + {"Bob", 55}, + } + firstOldest := slices.MaxFunc(people, func(a, b Person) int { + return cmp.Compare(a.Age, b.Age) + }) + fmt.Println(firstOldest.Name) + // Output: + // Alice +} + +func ExampleMin() { + numbers := []int{0, 42, -10, 8} + fmt.Println(slices.Min(numbers)) + // Output: + // -10 +} + +func ExampleMinFunc() { + type Person struct { + Name string + Age int + } + people := []Person{ + {"Gopher", 13}, + {"Bob", 5}, + {"Vera", 24}, + {"Bill", 5}, + } + firstYoungest := slices.MinFunc(people, func(a, b Person) int { + return cmp.Compare(a.Age, b.Age) + }) + fmt.Println(firstYoungest.Name) + // Output: + // Bob +} + +func ExampleReplace() { + names := []string{"Alice", "Bob", "Vera", "Zac"} + names = slices.Replace(names, 1, 3, "Bill", "Billie", "Cat") + fmt.Println(names) + // Output: + // [Alice Bill Billie Cat Zac] +} + +func ExampleReverse() { + names := []string{"alice", "Bob", "VERA"} + slices.Reverse(names) + fmt.Println(names) + // Output: + // [VERA Bob alice] +} + +func ExampleSort() { + smallInts := []int8{0, 42, -10, 8} + slices.Sort(smallInts) + fmt.Println(smallInts) + // Output: + // [-10 0 8 42] +} + +func ExampleSortFunc_caseInsensitive() { + names := []string{"Bob", "alice", "VERA"} + slices.SortFunc(names, func(a, b string) int { + return cmp.Compare(strings.ToLower(a), strings.ToLower(b)) + }) + fmt.Println(names) + // Output: + // [alice Bob VERA] +} + +func ExampleSortFunc_multiField() { + type Person struct { + Name string + Age int + } + people := []Person{ + {"Gopher", 13}, + {"Alice", 55}, + {"Bob", 24}, + {"Alice", 20}, + } + slices.SortFunc(people, func(a, b Person) int { + if n := cmp.Compare(a.Name, b.Name); n != 0 { + return n + } + // If names are equal, order by age + return cmp.Compare(a.Age, b.Age) + }) + fmt.Println(people) + // Output: + // [{Alice 20} {Alice 55} {Bob 24} {Gopher 13}] +} + +func ExampleSortStableFunc() { + type Person struct { + Name string + Age int + } + people := []Person{ + {"Gopher", 13}, + {"Alice", 20}, + {"Bob", 24}, + {"Alice", 55}, + } + // Stable sort by name, keeping age ordering of Alices intact + slices.SortStableFunc(people, func(a, b Person) int { + return cmp.Compare(a.Name, b.Name) + }) + fmt.Println(people) + // Output: + // [{Alice 20} {Alice 55} {Bob 24} {Gopher 13}] +} diff --git a/src/slices/slices.go b/src/slices/slices.go index 653d4dd093..afeed0afb5 100644 --- a/src/slices/slices.go +++ b/src/slices/slices.go @@ -27,7 +27,7 @@ func Equal[S ~[]E, E comparable](s1, s2 S) bool { return true } -// EqualFunc reports whether two slices are equal using a comparison +// EqualFunc reports whether two slices are equal using an equality // function on each pair of elements. If the lengths are different, // EqualFunc returns false. Otherwise, the elements are compared in // increasing index order, and the comparison stops at the first index @@ -210,7 +210,6 @@ func Insert[S ~[]E, E any](s S, i int, v ...E) S { // Delete removes the elements s[i:j] from s, returning the modified slice. // Delete panics if s[i:j] is not a valid slice of s. -// Delete modifies the contents of the slice s; it does not create a new slice. // Delete is O(len(s)-j), so if many items must be deleted, it is better to // make a single call deleting them all together than to delete one at a time. // Delete might not modify the elements s[len(s)-(j-i):len(s)]. If those @@ -224,8 +223,6 @@ func Delete[S ~[]E, E any](s S, i, j int) S { // DeleteFunc removes any elements from s for which del returns true, // returning the modified slice. -// DeleteFunc modifies the contents of the slice s; -// it does not create a new slice. // When DeleteFunc removes m elements, it might not modify the elements // s[len(s)-m:len(s)]. If those elements contain pointers you might consider // zeroing those elements so that objects they reference can be garbage @@ -348,7 +345,8 @@ func Clone[S ~[]E, E any](s S) S { // Compact replaces consecutive runs of equal elements with a single copy. // This is like the uniq command found on Unix. -// Compact modifies the contents of the slice s; it does not create a new slice. +// Compact modifies the contents of the slice s and returns the modified slice, +// which may have a smaller length. // When Compact discards m elements in total, it might not modify the elements // s[len(s)-m:len(s)]. If those elements contain pointers you might consider // zeroing those elements so that objects they reference can be garbage collected. @@ -368,7 +366,8 @@ func Compact[S ~[]E, E comparable](s S) S { return s[:i] } -// CompactFunc is like [Compact] but uses a comparison function. +// CompactFunc is like [Compact] but uses an equality function to compare elements. +// For runs of elements that compare equal, CompactFunc keeps the first one. func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S { if len(s) < 2 { return s diff --git a/src/slices/sort.go b/src/slices/sort.go index a634c12f6f..822f2fceb4 100644 --- a/src/slices/sort.go +++ b/src/slices/sort.go @@ -29,7 +29,7 @@ func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int) { } // SortStableFunc sorts the slice x while keeping the original order of equal -// elements, using cmp to compare elements. +// elements, using cmp to compare elements in the same way as [SortFunc]. func SortStableFunc[S ~[]E, E any](x S, cmp func(a, b E) int) { stableCmpFunc(x, len(x), cmp) } @@ -45,7 +45,7 @@ func IsSorted[S ~[]E, E cmp.Ordered](x S) bool { } // IsSortedFunc reports whether x is sorted in ascending order, with cmp as the -// comparison function. +// comparison function as defined by [SortFunc]. func IsSortedFunc[S ~[]E, E any](x S, cmp func(a, b E) int) bool { for i := len(x) - 1; i > 0; i-- { if cmp(x[i], x[i-1]) < 0 { |