2011-02-09 9 views
5

Se ho un allineamento/fetta di struct in Vai e desidera ordinare utilizzando il pacchetto di sorta mi sembra che ho bisogno di implementare l'intera interfaccia tipo che contiene 3 metodi:Vai: C'è un modo per evitare l'implementazione dell'intero ordinamento. Interfaccia per sezioni di strutture?

  • Len
  • Swap
  • Meno

sembra che Len e swap dovrebbe sempre avere la stessa implementazione non importa il tipo di struct è nella matrice.

C'è un modo per evitare di avere lo strumento Len e Swap ogni volta o è solo una limitazione della mancanza di Generics in Go?

risposta

5

La tua risposta è giusta. Nel tuo caso di array o slice le implementazioni di Len() e Swap() sono semplici. Come len() Go potrebbe fornire uno scambio nativo() qui. Ma l'interfaccia che viene ora utilizzata può anche essere utilizzata per strutture di dati più complesse come BTrees. Permette comunque alla funzione Sort() di funzionare (come il mio quicksort parallelo, che usa la stessa interfaccia di ordinamento).

7

Se si stanno implementando diverse operazioni di confronto sullo stesso tipo di slice, è possibile utilizzare l'incorporamento per evitare di ridefinire Len e Swap ogni volta. È inoltre possibile utilizzare questa tecnica per aggiungere parametri all'ordinamento, ad esempio per ordinare al contrario o meno a seconda del valore di runtime.

ad es.

package main 

import (
    "sort" 
) 

type T struct { 
    Foo int 
    Bar int 
} 

// TVector is our basic vector type. 
type TVector []T 

func (v TVector) Len() int { 
    return len(v) 
} 

func (v TVector) Swap(i, j int) { 
    v[i], v[j] = v[j], v[i] 
} 

// default comparison. 
func (v TVector) Less(i, j int) bool { 
    return v[i].Foo < v[j].Foo 
} 

// TVectorBarOrdered embeds TVector and overrides 
// its Less method so that it is ordered by the Bar field. 
type TVectorBarOrdered struct { 
    TVector 
} 

func (v TVectorBarOrdered) Less(i, j int) bool { 
    return v.TVector[i].Bar < v.TVector[j].Bar 
} 

// TVectorArbitraryOrdered sorts in normal or reversed 
// order depending on the order of its Reversed field. 
type TVectorArbitraryOrdered struct { 
    Reversed bool 
    TVector 
} 

func (v TVectorArbitraryOrdered) Less(i, j int) bool { 
    if v.Reversed { 
     i, j = j, i 
    } 
    return v.TVector[i].Foo < v.TVector[j].Foo 
} 

func main() { 
    v := []T{{1, 3}, {0, 6}, {3, 2}, {8, 7}} 
    sort.Sort(TVector(v)) 
    sort.Sort(TVectorBarOrdered{v}) 
    sort.Sort(TVectorArbitraryOrdered{true, v}) 
} 
+0

Molto interessante. Mi sono chiesto come utilizzare più ordinamenti sullo stesso tipo di Slice. –

0

Anche se questa è una vecchia questione, vorrei sottolineare il pacchetto github.com/bradfitz/slice . ma come esempio o la prova di un solo concetto, vorrei non raccomandare questo effettivamente utilizzato (è documentato con la parola "lordo"):

Esso utilizza le operazioni, di basso livello lordo per rendere più facile per ordinare fette arbitrarie con solo una funzione in meno, senza definire un nuovo tipo con le operazioni Len e Swap.

Nel codice vero e proprio, lo trovo del tutto banale, rapido, breve, leggibile, e non distrae per fare proprio qualcosa di simile:

type points []point 

func (p []points) Len() int  { return len(p) } 
func (p []points) Swap(i, j int) { p[i], p[j] = p[j], p[i] } 
func (p []points) Less(i, j int) bool { 
     // custom, often multi-line, comparison code here 
} 

Qui gofmt insiste su una riga vuota tra il type e func righe ma non ha problemi con più funzioni a una riga senza righe vuote e allinea correttamente i corpi delle funzioni. Trovo che questo sia un bel modulo compatto leggibile per queste cose.

quanto riguarda il tuo commento che:

Sembra che Len e swap dovrebbe sempre avere la stessa implementazione non importa il tipo di struct è nel [slice]

appena l'altra settimana ho bisogno di una specie che teneva coppie di elementi in una fetta insieme (per ingresso a strings.NewReplacer) che ha richiesto una variazione banale come:

type pairByLen []string 

func (p pairByLen) Len() int   { return len(p)/2 } 
func (p pairByLen) Less(i, j int) bool { return len(p[i*2]) > len(p[j*2]) } 
func (p pairByLen) Swap(i, j int) { 
     p[i*2], p[j*2] = p[j*2], p[i*2] 
     p[i*2+1], p[j*2+1] = p[j*2+1], p[i*2+1] 
} 

Questo non è supportato da un'interfaccia come quella di github.com/bradfitz/slice. Ancora una volta, trovo questo layout facile, compatto e leggibile. Anche se (forse di più in questo caso), altri potrebbero non essere d'accordo.

Problemi correlati