aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Hoyt <benhoyt@gmail.com>2023-06-23 00:35:45 +1200
committerGopher Robot <gobot@golang.org>2023-06-29 15:34:32 +0000
commit411c99671a6c6b6f59abe81d872db6daf2e1738a (patch)
tree3d745da44d775b2c3d49c312e623d4b98f006b8e
parent03cd8a7b0e47f2141a1dbdad9fdce175942d5515 (diff)
downloadgo-411c99671a6c6b6f59abe81d872db6daf2e1738a.tar.gz
go-411c99671a6c6b6f59abe81d872db6daf2e1738a.zip
slices, maps: add examples; doc comment fixes
There are currently no examples in the new slices and maps package, so add some. This adds examples for most functions in the slices package except the very obvious ones, and adds examples for the DeleteFunc and EqualFunc functions in the maps package. Also clarify/correct a few doc comments: * EqualFunc takes an "equality" function, not a "comparison" function * It's confusing for Delete and DeleteFunc to say they "do not create a new slice", as they do return a new slice. They already say they "return the modified slice" which is enough. * Similar for Compact, and mention that it returns the modified slice (and say why) * Note that CompactFunc keeps the first element in equal runs * Say what cmp is in SortStableFunc and IsSortedFunc * Say that MinFunc and MaxFunc return the first value Change-Id: I59c7bb1c7cabc4986d81018a5aaf5b712d3310f2 Reviewed-on: https://go-review.googlesource.com/c/go/+/505095 Reviewed-by: Carlos Amedee <carlos@golang.org> Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Run-TryBot: Ian Lance Taylor <iant@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
-rw-r--r--src/maps/example_test.go45
-rw-r--r--src/slices/example_test.go322
-rw-r--r--src/slices/slices.go11
-rw-r--r--src/slices/sort.go4
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 {