diff --git a/src/cmp/cmp.go b/src/cmp/cmp.go index a13834c3985892..35214ca9092144 100644 --- a/src/cmp/cmp.go +++ b/src/cmp/cmp.go @@ -75,3 +75,22 @@ func Or[T comparable](vals ...T) T { } return zero } + +// CompareBy returns a comparison function for values of type V. +// The comparison is based on a key function that transforms each value +// of type V into a comparable type K (which must satisfy the Ordered constraint). +// The resulting comparison function can be used in sorting or other comparisons. +// +// This is similar to Python's key functions and integrates well with +// other proposed features like Reverse (#65632). +// +// Example usage: +// +// people := []Person{{"Alice", 30}, {"Bob", 25}} +// sort.Slice(people, cmp.CompareBy(func(p Person) int { return p.Age })) +func CompareBy[K Ordered, V any](key func(V) K) func(V, V) int { + return func(a, b V) int { + // Compare the transformed values using the Compare function + return Compare(key(a), key(b)) + } +} diff --git a/src/cmp/cmp_test.go b/src/cmp/cmp_test.go index 43d9ef365e2d48..099acdbb3fce95 100644 --- a/src/cmp/cmp_test.go +++ b/src/cmp/cmp_test.go @@ -176,3 +176,30 @@ func ExampleOr_sort() { // bar carol 1.00 // baz carol 4.00 } + +func TestCompareBy(t *testing.T) { + type Person struct { + Name string + Age int + } + + // Key function to extract age for comparison + byAge := cmp.CompareBy(func(p Person) int { + return p.Age + }) + + // Test data + alice := Person{Name: "Alice", Age: 30} + bob := Person{Name: "Bob", Age: 25} + + // Test comparisons + if got := byAge(alice, bob); got <= 0 { + t.Errorf("expected Alice > Bob by age, got %d", got) + } + if got := byAge(bob, alice); got >= 0 { + t.Errorf("expected Bob < Alice by age, got %d", got) + } + if got := byAge(alice, alice); got != 0 { + t.Errorf("expected Alice == Alice by age, got %d", got) + } +}