[go] sort: new example: SliceStable examples to demonstrate sorting slices

297 views
Skip to first unread message

Kenny Grant (Gerrit)

unread,
Feb 18, 2017, 12:13:23 PM2/18/17
to Ian Lance Taylor, golang-co...@googlegroups.com

Kenny Grant has uploaded this change for review.

View Change

sort: new example: SliceStable examples to demonstrate sorting slices

ExampleSliceStable echoes sort.Slice example, to demonstrate sorting
on two fields at together.

Example_sortSliceStable offers a shorter version of Example_sortMultiKeys
using the new sort.SliceStable.

Change-Id: I8afc20c0203991bfd57260431eda73913c165355
---
A src/sort/example_slice_stable_test.go
M src/sort/example_test.go
2 files changed, 77 insertions(+), 0 deletions(-)

diff --git a/src/sort/example_slice_stable_test.go b/src/sort/example_slice_stable_test.go
new file mode 100644
index 0000000..fc30981
--- /dev/null
+++ b/src/sort/example_slice_stable_test.go
@@ -0,0 +1,56 @@
+// Copyright 2013 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 sort_test
+
+import (
+	"fmt"
+	"sort"
+)
+
+// Person has a Name and an Age.
+type Person struct {
+	Name string
+	Age  int
+}
+
+// PeopleSorter defines functions for sorting people on name and age.
+type PeopleSorter []Person
+
+func (p PeopleSorter) ByName(i, j int) bool {
+	return p[i].Name < p[j].Name
+}
+func (p PeopleSorter) ByAge(i, j int) bool {
+	return p[i].Age < p[j].Age
+}
+func (p PeopleSorter) Sort(functions ...func(i, j int) bool) {
+	for _, fn := range functions {
+		sort.SliceStable(p, fn)
+	}
+}
+
+// ExampleSliceStable demonstrates sorting a slice of structs by two fields
+// using sort.SliceStable.
+func Example_sortSliceStable() {
+
+	people := PeopleSorter{
+		{"Gopher", 55},
+		{"Alice", 55},
+		{"Alice", 23},
+		{"Vera", 23},
+		{"Bob", 56},
+		{"Ava", 2},
+	}
+
+	// Sort by name then age, so that age takes priority.
+	people.Sort(people.ByName, people.ByAge)
+	fmt.Println("Sorted by age,name:", people)
+
+	// Sort by age then name, so that name takes priority.
+	people.Sort(people.ByAge, people.ByName)
+	fmt.Println("Sorted by name,age:", people)
+
+	// Output: Sorted by age,name: [{Ava 2} {Alice 23} {Vera 23} {Alice 55} {Gopher 55} {Bob 56}]
+	// Sorted by name,age: [{Alice 23} {Alice 55} {Ava 2} {Bob 56} {Gopher 55} {Vera 23}]
+}
diff --git a/src/sort/example_test.go b/src/sort/example_test.go
index 980c0d0..87b0156 100644
--- a/src/sort/example_test.go
+++ b/src/sort/example_test.go
@@ -41,3 +41,24 @@
 	// Output: By name: [{Alice 55} {Bob 75} {Gopher 7} {Vera 24}]
 	// By age: [{Gopher 7} {Vera 24} {Alice 55} {Bob 75}]
 }
+
+func ExampleSliceStable() {
+	people := []struct {
+		Name string
+		Age  int
+	}{
+		{"Gopher", 7},
+		{"Goph", 17},
+		{"Alice", 55},
+		{"Alice", 51},
+		{"Vera", 24},
+		{"Bob", 75},
+	}
+	sort.SliceStable(people, func(i, j int) bool { return people[i].Name < people[j].Name })
+	fmt.Println("By name:", people)
+
+	sort.SliceStable(people, func(i, j int) bool { return people[i].Age < people[j].Age })
+	fmt.Println("By name, then by age:", people)
+	// Output: By name: [{Alice 55} {Alice 51} {Bob 75} {Goph 17} {Gopher 7} {Vera 24}]
+	// By name, then by age: [{Gopher 7} {Goph 17} {Vera 24} {Alice 51} {Alice 55} {Bob 75}]
+}

To view, visit change 37196. To unsubscribe, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I8afc20c0203991bfd57260431eda73913c165355
Gerrit-Change-Number: 37196
Gerrit-PatchSet: 1
Gerrit-Owner: Kenny Grant <kenny...@gmail.com>

Kenny Grant (Gerrit)

unread,
Feb 18, 2017, 12:45:18 PM2/18/17
to golang-co...@googlegroups.com

Kenny Grant uploaded patch set #2 to this change.

View Change

sort: new example: SliceStable examples to demonstrate sorting slices

ExampleSliceStable echoes the sort.Slice example, to demonstrate sorting
on two fields together rather than separately as in sort.Slice.

Example_sortSliceStable offers a shorter version of Example_sortMultiKeys
using the new sort.SliceStable and a slice type to sort on multiple keys.

Change-Id: I8afc20c0203991bfd57260431eda73913c165355
---
A src/sort/example_slice_stable_test.go
M src/sort/example_test.go
2 files changed, 77 insertions(+), 0 deletions(-)

To view, visit change 37196. To unsubscribe, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-MessageType: newpatchset
Gerrit-Change-Id: I8afc20c0203991bfd57260431eda73913c165355
Gerrit-Change-Number: 37196
Gerrit-PatchSet: 2
Gerrit-Owner: Kenny Grant <kenny...@gmail.com>

Brad Fitzpatrick (Gerrit)

unread,
Feb 18, 2017, 5:20:38 PM2/18/17
to Kenny Grant, Brad Fitzpatrick, golang-co...@googlegroups.com

Brad Fitzpatrick posted comments on this change.

View Change

Patch set 2:

(3 comments)

To view, visit change 37196. To unsubscribe, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-MessageType: comment
Gerrit-Change-Id: I8afc20c0203991bfd57260431eda73913c165355
Gerrit-Change-Number: 37196
Gerrit-PatchSet: 2
Gerrit-Owner: Kenny Grant <kenny...@gmail.com>
Gerrit-CC: Brad Fitzpatrick <brad...@golang.org>
Gerrit-Comment-Date: Sat, 18 Feb 2017 22:20:36 +0000
Gerrit-HasComments: Yes

Kenny Grant (Gerrit)

unread,
Feb 18, 2017, 7:27:52 PM2/18/17
to Brad Fitzpatrick, golang-co...@googlegroups.com

Kenny Grant uploaded patch set #3 to this change.

View Change

sort: new example: Sorting slices with sort.SliceStable

ExampleSliceStable echoes the sort.Slice example, to demonstrate sorting
on two fields together preserving order between sorts.

ExampleMultiKeysStable demonstrates sorting on multiple keys
using a slice wrapper which defines sort functions.

Change-Id: I8afc20c0203991bfd57260431eda73913c165355
---
A src/sort/example_slice_stable_test.go
M src/sort/example_test.go
2 files changed, 94 insertions(+), 0 deletions(-)

To view, visit change 37196. To unsubscribe, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-MessageType: newpatchset
Gerrit-Change-Id: I8afc20c0203991bfd57260431eda73913c165355
Gerrit-Change-Number: 37196
Gerrit-PatchSet: 3

Kenny Grant (Gerrit)

unread,
Feb 18, 2017, 7:33:17 PM2/18/17
to Brad Fitzpatrick, golang-co...@googlegroups.com

Kenny Grant posted comments on this change.

View Change

Patch set 2:

Patch Set 2: Oh, there it is!

A few notes on this which I hope will explain the motivation:

The simple example was intended as the illustration of sort.SliceStable.

I know you anticipated sort.SliceStable being used with inline functions, the more complex example was intended to replace example_multi_test - it does the same thing so I've tweaked it to make this clearer and use the same data. Personally now we have sort.SliceStable I would use that instead of the example_multi_test method using interfaces because:

1. Order is preserved (the example_multi_test does not do this, see the language,<lines sort). 2. It is shorter and clearer than example_multi_test 3. This shifts complexity over to the slice wrapper from the calling site (SortBy, sort funcs), so sorting becomes one line but is still clear.

Obviously if you use multiSorter once it's pointless, but if you had a slice wrapper anyway for the data, and sort it in several different places in this sort of way, and/or have complex sorting requirements which mean the inline sorting functions would get ugly, it would be handy.

I wasn't sure if you'd want to get rid of the multi_test, but I wonder if it's no longer necc. because of the addition of sort.SliceStable, which can do the same thing in a simpler way as seen here. I hope this helps clarify a bit - example_multi_test could maybe be replaced by this method.

    To view, visit change 37196. To unsubscribe, visit settings.

    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-MessageType: comment
    Gerrit-Change-Id: I8afc20c0203991bfd57260431eda73913c165355
    Gerrit-Change-Number: 37196
    Gerrit-PatchSet: 2
    Gerrit-Owner: Kenny Grant <kenny...@gmail.com>
    Gerrit-Reviewer: Kenny Grant <kenny...@gmail.com>
    Gerrit-CC: Brad Fitzpatrick <brad...@golang.org>
    Gerrit-Comment-Date: Sun, 19 Feb 2017 00:33:14 +0000
    Gerrit-HasComments: No

    Kenny Grant (Gerrit)

    unread,
    Feb 21, 2017, 4:25:28 AM2/21/17
    to Brad Fitzpatrick, golang-co...@googlegroups.com

    Kenny Grant uploaded patch set #4 to this change.

    View Change

    sort: new example: Sorting slices with sort.SliceStable
    
    ExampleSliceStable echoes the sort.Slice example, to demonstrate sorting
    on two fields together preserving order between sorts.
    
    Change-Id: I8afc20c0203991bfd57260431eda73913c165355
    ---
    M src/sort/example_test.go
    1 file changed, 21 insertions(+), 0 deletions(-)
    
    

    To view, visit change 37196. To unsubscribe, visit settings.

    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-MessageType: newpatchset
    Gerrit-Change-Id: I8afc20c0203991bfd57260431eda73913c165355
    Gerrit-Change-Number: 37196
    Gerrit-PatchSet: 4

    Kenny Grant (Gerrit)

    unread,
    Feb 21, 2017, 4:28:52 AM2/21/17
    to Brad Fitzpatrick, golang-co...@googlegroups.com

    Kenny Grant posted comments on this change.

    View Change

    Patch set 4:

    Uploaded patch set 4.

    I've removed the larger example for now, to make this easier to review. Hopefully the smaller SliceStable example is fine to merge as is.

    Let me know if it is worth submitting a change to example_multi_test - I think now that we have slice.Sort... we should have an example at the top of the docs which uses that (as well as example_keys_test which uses Len/Swap/Less), but if you'd rather not I can just drop it.

    (1 comment)

      • wrong year

        Done

    To view, visit change 37196. To unsubscribe, visit settings.

    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-MessageType: comment
    Gerrit-Change-Id: I8afc20c0203991bfd57260431eda73913c165355
    Gerrit-Change-Number: 37196
    Gerrit-PatchSet: 4
    Gerrit-Owner: Kenny Grant <kenny...@gmail.com>
    Gerrit-Reviewer: Kenny Grant <kenny...@gmail.com>
    Gerrit-CC: Brad Fitzpatrick <brad...@golang.org>
    Gerrit-Comment-Date: Tue, 21 Feb 2017 09:28:49 +0000
    Gerrit-HasComments: Yes

    Volker Dobler (Gerrit)

    unread,
    Feb 21, 2017, 5:22:09 AM2/21/17
    to Kenny Grant, Brad Fitzpatrick, golang-co...@googlegroups.com

    Volker Dobler posted comments on this change.

    View Change

    Patch set 4:

    (3 comments)

    • File src/sort/example_test.go:

      • Patch Set #4, Line 57: sort.SliceStable(people, func(i, j int) bool { return people[i].Name < people[j].Name })

        The example is not a good one: Sorting unstable with sort.Slice yields the same result. It will be hard to come up with a small example which does not only show the calling convention of SliceStable but its behaviour in contrast to Sort.

      • Patch Set #4, Line 60: sort.SliceStable(people, func(i, j int) bool { return people[i].Age < people[j].Age })

        Stable sorting people by Age where all Ages are distinct is pretty useless: A normal (unstable) Sort would produce the exact same output. The nice thing about stable sorting is that you can sort twice (as you do here by Name and by Age) and the relative order generated by the first sorting is kept during the second sorting: The final result will be Age-sorted but each same-Age-block will be sorted alphabetically by Name. To show this nice feature you need an input set with several multiple Age values. Probably something like three Names times three Ages.

      • Patch Set #4, Line 62: // Output: By name: [{Alice 55} {Alice 51} {Bob 75} {Goph 17} {Gopher 7} {Vera 24}]

        Is there a reason to not start a new line after Output: ? (For single line outputs a single "Output: <whatever>" line is fine but it seems odd for multi line expected output.)

    To view, visit change 37196. To unsubscribe, visit settings.

    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-MessageType: comment
    Gerrit-Change-Id: I8afc20c0203991bfd57260431eda73913c165355
    Gerrit-Change-Number: 37196
    Gerrit-PatchSet: 4
    Gerrit-Owner: Kenny Grant <kenny...@gmail.com>
    Gerrit-Reviewer: Kenny Grant <kenny...@gmail.com>
    Gerrit-CC: Brad Fitzpatrick <brad...@golang.org>
    Gerrit-CC: Volker Dobler <dr.volke...@gmail.com>
    Gerrit-Comment-Date: Tue, 21 Feb 2017 10:22:05 +0000
    Gerrit-HasComments: Yes

    Kenny Grant (Gerrit)

    unread,
    Feb 21, 2017, 6:57:20 AM2/21/17
    to Brad Fitzpatrick, golang-co...@googlegroups.com

    Kenny Grant uploaded patch set #5 to this change.

    View Change

    sort: new example: Sorting slices with sort.SliceStable
    
    ExampleSliceStable echoes the sort.Slice example, to demonstrate sorting
    on two fields together preserving order between sorts.
    
    Change-Id: I8afc20c0203991bfd57260431eda73913c165355
    ---
    M src/sort/example_test.go
    1 file changed, 28 insertions(+), 0 deletions(-)
    
    

    To view, visit change 37196. To unsubscribe, visit settings.

    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-MessageType: newpatchset
    Gerrit-Change-Id: I8afc20c0203991bfd57260431eda73913c165355
    Gerrit-Change-Number: 37196
    Gerrit-PatchSet: 5

    Kenny Grant (Gerrit)

    unread,
    Feb 21, 2017, 7:09:15 AM2/21/17
    to Brad Fitzpatrick, golang-co...@googlegroups.com

    Kenny Grant uploaded patch set #6 to this change.

    View Change

    sort: new example: Sorting slices with sort.SliceStable
    
    ExampleSliceStable echoes the sort.Slice example, to demonstrate sorting
    on two fields together preserving order between sorts.
    
    Change-Id: I8afc20c0203991bfd57260431eda73913c165355
    ---
    M src/sort/example_test.go
    1 file changed, 28 insertions(+), 0 deletions(-)
    
    

    To view, visit change 37196. To unsubscribe, visit settings.

    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-MessageType: newpatchset
    Gerrit-Change-Id: I8afc20c0203991bfd57260431eda73913c165355
    Gerrit-Change-Number: 37196
    Gerrit-PatchSet: 6

    Kenny Grant (Gerrit)

    unread,
    Feb 21, 2017, 7:13:31 AM2/21/17
    to Brad Fitzpatrick, golang-co...@googlegroups.com

    Kenny Grant posted comments on this change.

    View Change

    Patch set 6:

    Patch Set 4: (3 comments)

    Thanks, I've uploaded a new version with a different set of names/ages to sort. Re specific points comments below.

    (3 comments)

      • The example is not a good one: Sorting unstable with sort.Slice yields the

      • I think it's fine to use SliceStable here as that's what the test is for, I've aded a comment to indicate it preserves existing order here (unlike sort.Slice which may or may not).

      • Stable sorting people by Age where all Ages are distinct is pretty useless:

        Yes this was a bad set of ages as sort.Slice would return the same results, I've adjusted the set of names/ages used so that now it consistently returns different results for Slice vs SliceStable - this required a few entries, just Alice and Bob for example won't give different results:

        https://play.golang.org/p/wEY6sgTSMd

      • Patch Set #4, Line 62: sort.SliceStable(people, func(i, j int) bool { return people[i].Name < people[j].Name })

      • Is there a reason to not start a new line after Output: ?

      • Consistency with other tests in the same file, I don't think this really matters, would rather not edit other tests.

    To view, visit change 37196. To unsubscribe, visit settings.

    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-MessageType: comment
    Gerrit-Change-Id: I8afc20c0203991bfd57260431eda73913c165355
    Gerrit-Change-Number: 37196
    Gerrit-PatchSet: 6
    Gerrit-Owner: Kenny Grant <kenny...@gmail.com>
    Gerrit-Reviewer: Kenny Grant <kenny...@gmail.com>
    Gerrit-CC: Brad Fitzpatrick <brad...@golang.org>
    Gerrit-CC: Volker Dobler <dr.volke...@gmail.com>
    Gerrit-Comment-Date: Tue, 21 Feb 2017 12:13:28 +0000
    Gerrit-HasComments: Yes

    Brad Fitzpatrick (Gerrit)

    unread,
    Feb 22, 2017, 4:13:48 PM2/22/17
    to Kenny Grant, Brad Fitzpatrick, golang-co...@googlegroups.com

    Brad Fitzpatrick posted comments on this change.

    View Change

    Patch set 6:Run-TryBot +1Code-Review +2

      To view, visit change 37196. To unsubscribe, visit settings.

      Gerrit-Project: go
      Gerrit-Branch: master
      Gerrit-MessageType: comment
      Gerrit-Change-Id: I8afc20c0203991bfd57260431eda73913c165355
      Gerrit-Change-Number: 37196
      Gerrit-PatchSet: 6
      Gerrit-Owner: Kenny Grant <kenny...@gmail.com>
      Gerrit-Reviewer: Brad Fitzpatrick <brad...@golang.org>
      Gerrit-Reviewer: Kenny Grant <kenny...@gmail.com>
      Gerrit-CC: Volker Dobler <dr.volke...@gmail.com>
      Gerrit-Comment-Date: Wed, 22 Feb 2017 21:13:46 +0000
      Gerrit-HasComments: No

      Gobot Gobot (Gerrit)

      unread,
      Feb 22, 2017, 4:14:38 PM2/22/17
      to Kenny Grant, Brad Fitzpatrick, golang-co...@googlegroups.com

      Gobot Gobot posted comments on this change.

      View Change

      Patch set 6:

      TryBots beginning. Status page: http://farmer.golang.org/try?commit=5ed98381

        To view, visit change 37196. To unsubscribe, visit settings.

        Gerrit-Project: go
        Gerrit-Branch: master
        Gerrit-MessageType: comment
        Gerrit-Change-Id: I8afc20c0203991bfd57260431eda73913c165355
        Gerrit-Change-Number: 37196
        Gerrit-PatchSet: 6
        Gerrit-Owner: Kenny Grant <kenny...@gmail.com>
        Gerrit-Reviewer: Brad Fitzpatrick <brad...@golang.org>
        Gerrit-Reviewer: Kenny Grant <kenny...@gmail.com>
        Gerrit-CC: Gobot Gobot <go...@golang.org>
        Gerrit-CC: Volker Dobler <dr.volke...@gmail.com>
        Gerrit-Comment-Date: Wed, 22 Feb 2017 21:14:35 +0000
        Gerrit-HasComments: No

        Gobot Gobot (Gerrit)

        unread,
        Feb 22, 2017, 4:22:54 PM2/22/17
        to Kenny Grant, Brad Fitzpatrick, golang-co...@googlegroups.com

        Gobot Gobot posted comments on this change.

        View Change

        Patch set 6:TryBot-Result +1

        TryBots are happy.

          To view, visit change 37196. To unsubscribe, visit settings.

          Gerrit-Project: go
          Gerrit-Branch: master
          Gerrit-MessageType: comment
          Gerrit-Change-Id: I8afc20c0203991bfd57260431eda73913c165355
          Gerrit-Change-Number: 37196
          Gerrit-PatchSet: 6
          Gerrit-Owner: Kenny Grant <kenny...@gmail.com>
          Gerrit-Reviewer: Brad Fitzpatrick <brad...@golang.org>
          Gerrit-Reviewer: Gobot Gobot <go...@golang.org>
          Gerrit-Reviewer: Kenny Grant <kenny...@gmail.com>
          Gerrit-CC: Volker Dobler <dr.volke...@gmail.com>
          Gerrit-Comment-Date: Wed, 22 Feb 2017 21:22:52 +0000
          Gerrit-HasComments: No

          Brad Fitzpatrick (Gerrit)

          unread,
          Feb 22, 2017, 4:23:16 PM2/22/17
          to Brad Fitzpatrick, Kenny Grant, golang-...@googlegroups.com, Gobot Gobot, golang-co...@googlegroups.com

          Brad Fitzpatrick merged this change.

          View Change

          Approvals: Brad Fitzpatrick: Looks good to me, approved; Run TryBots Gobot Gobot: TryBots succeeded
          sort: new example: Sorting slices with sort.SliceStable
          
          ExampleSliceStable echoes the sort.Slice example, to demonstrate sorting
          on two fields together preserving order between sorts.
          
          Change-Id: I8afc20c0203991bfd57260431eda73913c165355
          Reviewed-on: https://go-review.googlesource.com/37196
          Reviewed-by: Brad Fitzpatrick <brad...@golang.org>
          Run-TryBot: Brad Fitzpatrick <brad...@golang.org>
          TryBot-Result: Gobot Gobot <go...@golang.org>
          ---
          M src/sort/example_test.go
          1 file changed, 28 insertions(+), 0 deletions(-)
          
          
          diff --git a/src/sort/example_test.go b/src/sort/example_test.go
          index 980c0d0..89ebe79 100644
          --- a/src/sort/example_test.go
          +++ b/src/sort/example_test.go
          @@ -41,3 +41,31 @@
           	// Output: By name: [{Alice 55} {Bob 75} {Gopher 7} {Vera 24}]
           	// By age: [{Gopher 7} {Vera 24} {Alice 55} {Bob 75}]
           }
          +
          +func ExampleSliceStable() {
          +
          +	people := []struct {
          +		Name string
          +		Age  int
          +	}{
          +		{"Alice", 25},
          +		{"Elizabeth", 75},
          +		{"Alice", 75},
          +		{"Bob", 75},
          +		{"Alice", 75},
          +		{"Bob", 25},
          +		{"Colin", 25},
          +		{"Elizabeth", 25},
          +	}
          +
          +	// Sort by name, preserving original order
          +	sort.SliceStable(people, func(i, j int) bool { return people[i].Name < people[j].Name })
          +	fmt.Println("By name:", people)
          +
          +	// Sort by age preserving name order
          +	sort.SliceStable(people, func(i, j int) bool { return people[i].Age < people[j].Age })
          +	fmt.Println("By age,name:", people)
          +
          +	// Output: By name: [{Alice 25} {Alice 75} {Alice 75} {Bob 75} {Bob 25} {Colin 25} {Elizabeth 75} {Elizabeth 25}]
          +	// By age,name: [{Alice 25} {Bob 25} {Colin 25} {Elizabeth 25} {Alice 75} {Alice 75} {Bob 75} {Elizabeth 75}]
          +}
          

          To view, visit change 37196. To unsubscribe, visit settings.

          Gerrit-Project: go
          Gerrit-Branch: master
          Gerrit-MessageType: merged
          Gerrit-Change-Id: I8afc20c0203991bfd57260431eda73913c165355
          Gerrit-Change-Number: 37196
          Gerrit-PatchSet: 7
          Reply all
          Reply to author
          Forward
          0 new messages