diff --git a/orderBy.go b/orderBy.go index 4f666ee..5d32c37 100644 --- a/orderBy.go +++ b/orderBy.go @@ -1,27 +1,21 @@ package underscore +import "slices" + // OrderBy orders a slice by a field value within a struct, the predicate allows you // to pick the fields you want to orderBy. Use > for ASC or < for DESC +// Uses O(n log n) sorting algorithm. Mutates the input slice. // // func (left Person, right Person) bool { return left.Age > right.Age } func OrderBy[T any](list []T, predicate func(T, T) bool) []T { - swaps := true - var tmp T - - //todo: replace with a faster algorithm, this one is pretty simple - for swaps { - swaps = false - - for i := 0; i < len(list)-1; i++ { - if predicate(list[i], list[i+1]) { - swaps = true - tmp = list[i] - - list[i] = list[i+1] - list[i+1] = tmp - } + slices.SortFunc(list, func(a, b T) int { + if predicate(a, b) { + return 1 } - } - + if predicate(b, a) { + return -1 + } + return 0 + }) return list } diff --git a/orderBy_test.go b/orderBy_test.go index ac0d802..0fcf105 100644 --- a/orderBy_test.go +++ b/orderBy_test.go @@ -29,3 +29,31 @@ func Test_OrderBy_Desc(t *testing.T) { assert.Equal(t, want, result) } + +func BenchmarkOrderBy(b *testing.B) { + data := make([]int, 1000) + for i := range data { + data[i] = 1000 - i // Reverse order - worst case for bubble sort + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + dataCopy := make([]int, len(data)) + copy(dataCopy, data) + u.OrderBy(dataCopy, func(a, b int) bool { return a > b }) + } +} + +func BenchmarkOrderBySmall(b *testing.B) { + data := make([]int, 10) + for i := range data { + data[i] = 10 - i + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + dataCopy := make([]int, len(data)) + copy(dataCopy, data) + u.OrderBy(dataCopy, func(a, b int) bool { return a > b }) + } +}