-2

I do have

4, 5', 6, 5''

and want to reverse stable sort as

6, 5', 5'', 4

but not

6, 5'', 5', 4

This (invalid) code would not work

keys := []int{4, 5', 6, 5''}
sort.Stable(sort.Reverse(sort.Ints(keys)))

it would produce:

6, 5'', 5', 4

Here the problem is shown as simplified as a slice of integers, but In reality I need to use it applied to a slice of structs

type myStruct struct {
    t time.Time
    d time.Duration
}

and reverse stable sort based in the t field.


Edit: After few comments I made explicit that the integer one is a non working example to simplify the problem.

Lorenzo Belli
  • 1,767
  • 4
  • 25
  • 46

3 Answers3

2

Implement the sort.Interface interface on a slice type, so you can choose the sort order, and apply a stable sort on it. Example : https://play.golang.org/p/TWAtH7asi3

Elwinar
  • 9,103
  • 32
  • 40
  • I looked at that however the behaviour I am looking for is not the same as 'reverse and stable sort'. I want the ordering of equal element to be applied as in the original list, and not as in the reversed one. – Lorenzo Belli Jan 15 '17 at 21:07
  • Well, unless I'm mistaken about your example, the code I provided works and would produce your first example. – Elwinar Jan 15 '17 at 21:11
  • HA! I see what you did. You implemented Less() as '>'. That's smart. – Lorenzo Belli Jan 15 '17 at 21:18
  • @LorenzoBelli: Elwinar did _not_ suppose to reverse after stable sorting: He proposed to stable sort with `Less` checking for more. His answer is correct. – Volker Jan 15 '17 at 21:19
  • 2
    You can still use `sort.Reverse` with a normal definition of `Less`. Did you try it? See https://play.golang.org/p/s8FezweFOj. – Andy Schweig Jan 15 '17 at 22:05
  • True that. The implementation of `sort.Reverse` is simply a type that implements `sort.Interface`, and reverse the results to `Less`. In fact, it should work too. That being said, depending on if your "reverse sort" is supposed to be the normal way to sort your values, I would advise to implement the interface using whatever definition of "i should be before j" and don't worry about the "integer sorting": if you're sorting scores for example, you'll want the biggest first. – Elwinar Jan 15 '17 at 22:18
  • @AndySchweig That is very very useful. That is not what I would have expected: `sort.Stable(sort.Reverse(w))` does not behave the same as reversing and stable sorting! – Lorenzo Belli Jan 17 '17 at 12:48
1

Implement the sort.Interface interface on your custom struct.

type myStruct struct{
    t time.Time
    d time.Duration
}

type Slice []myStruct

func (s Slice) Len() int {  return len(s) }

func (s Slice) Less(i, j int) bool {
    return (s[i].t).After(s[j].t)
}

func (s Slice) Swap(i, j int) {
    s[i], s[j] = s[j], s[i]
}

In your case, following function will sort in reverse order based on t

func (s Slice) Less(i, j int) bool {
    return (s[i].t).After(s[j].t)
}

(s[i].t).After(s[j].t) reports whether s[i].t is after s[j].t.

If you want only sort, use following one

func (s Slice) Less(i, j int) bool {
    return (s[i].t).Before(s[j].t)
}

Hope this will help.

Shahriar
  • 13,460
  • 8
  • 78
  • 95
0

It seems you don't need to go through the trouble of implementing the sort interface. You can just sort bare using sort.Slice or sort.SliceStable.

Here is what worked for me (go playground):

package main

import (
    "fmt"
    "sort"
    "time"
)

func main() {
    layout := "Jan 2 15:04:05 -0700 MST 2006"
    t1, _ := time.Parse(layout, "Jan 2 15:04:05 -0700 MST 2008")
    t2, _ := time.Parse(layout, "Jan 2 15:04:05 -0700 MST 2001")
    t3, _ := time.Parse(layout, "Jan 2 15:04:05 -0700 MST 2003")
    t4, _ := time.Parse(layout, "Jan 2 15:04:05 -0700 MST 2006")

    timestamps := []struct {
        T time.Time
        d time.Duration
    }{
        {t1, 1},
        {t2, 1},
        {t3, 1},
        {t4, 1},
    }

    // forward
    sort.Slice(timestamps, func(i, j int) bool { 
        return timestamps[i].T.Before(timestamps[j].T) 
    })
    fmt.Println("By time:", timestamps)

    // reverse
    sort.Slice(timestamps, func(i, j int) bool { 
        return timestamps[i].T.After(timestamps[j].T) 
    })
    fmt.Println("By time:", timestamps)
}
blobdon
  • 1,176
  • 7
  • 11