2013-10-08 46 views
28

http://play.golang.org/p/W70J4GU7nACome si inverte una matrice in Go?

s := []int{5, 2, 6, 3, 1, 4} 
    sort.Reverse(sort.IntSlice(s)) 
    fmt.Println(s) 
    // 5, 2, 6, 3, 1, 4 

E 'difficile capire cosa significa in Reverse func (interfaccia dati) Interface.

Come si inverte un array? Non ho bisogno di ordinare.

+0

Vedere http://stackoverflow.com/questions/18343208/how-to-reverse-sort-a-slice-of-integer-golang. Penso che tu debba usare 'Sort' per farlo facilmente. – Intermernet

risposta

16

Normalmente, per ordinare una matrice di numeri interi li si avvolge in un IntSlice, che definisce i metodi Len, Less e Swap. Questi metodi sono a loro volta utilizzati da sort.Sort. Che sort.Reverse fa è che ci vuole un tipo esistente che definisce Len, Less, e Swap, ma sostituisce il metodo Less con uno nuovo che è sempre l'inverso del sottostante Less:

type reverse struct { 
    // This embedded Interface permits Reverse to use the methods of 
    // another Interface implementation. 
    Interface 
} 

// Less returns the opposite of the embedded implementation's Less method. 
func (r reverse) Less(i, j int) bool { 
    return r.Interface.Less(j, i) 
} 

// Reverse returns the reverse order for data. 
func Reverse(data Interface) Interface { 
    return &reverse{data} 
} 

Così, quando si scrive sort.Reverse(sort.IntSlice(s)), che cosa sta succedendo è che stai ricevendo questo nuovo, 'modificato' IntSlice che ha il suo metodo Less sostituito. Quindi se si chiama sort.Sort su di esso, che chiama Less, verrà ordinato in ordine decrescente.

3
func Reverse(data Interface) Interface 

Questo significa che ci vuole un sort.Interface e restituisce un'altra sort.Interface - in realtà non fare alcuna selezione stessa. Ad esempio, se si passa in sort.IntSlice (che è essenzialmente un che può essere passato a sort.Sort per ordinarlo in ordine crescente) si otterrà un nuovo sort.Interface che ordina invece gli interi in ordine decrescente.

A proposito, se si fa clic sul nome della funzione in the documentation, si collega direttamente a the source per Reverse. Come puoi vedere, avvolge semplicemente lo sort.Interface che hai passato, quindi il valore restituito da Reverse ottiene tutti i metodi dell'originale sort.Interface. L'unico metodo diverso è il metodo Less che restituisce l'opposto del metodo Less sullo sort.Interface incorporato. Vedere this part of the language spec per i dettagli sui campi incorporati.

64

Onestamente questo è abbastanza semplice che avevo appena scrivo come questo:

package main 

import "fmt" 

func main() { 

    s := []int{5, 2, 6, 3, 1, 4} 

    for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { 
     s[i], s[j] = s[j], s[i] 
    } 

    fmt.Println(s) 
} 

http://play.golang.org/p/vkJg_D1yUb

(Le altre risposte fanno un buon lavoro di spiegare Interface e come usarlo; quindi non lo ripeterò.)

4

Se si desidera invertire l'array, è sufficiente eseguirlo in ordine inverso. Poiché non esiste un "range inversa" primitive nel linguaggio (almeno non ancora), è necessario fare qualcosa di simile (http://play.golang.org/p/AhvAfMjs_7):

s := []int{5, 2, 6, 3, 1, 4} 
for i := len(s) - 1; i >= 0; i-- { 
    fmt.Print(s[i]) 
    if i > 0 { 
     fmt.Print(", ") 
    } 
} 
fmt.Println() 

per quanto riguarda se è difficile capire che cosa sort.Reverse(data Interface) Interface fa, ho pensato che la lo stesso finché non ho visto il codice sorgente da "http://golang.org/src/pkg/sort/sort.go".

Questo rende solo i confronti necessari per l'ordinamento da effettuare "al contrario".

7

Sono in ritardo di 2 anni, ma solo per divertimento e interesse mi piacerebbe contribuire con una soluzione "strana".

Supponendo che il compito sia in realtà quello di invertire un elenco, quindi per la prestazione raw la soluzione di bgp è probabilmente imbattibile. Il lavoro viene svolto in modo semplice ed efficace sostituendo gli elementi dell'array da fronte a retro, un'operazione efficiente nella struttura ad accesso casuale di array e slice.

Nei linguaggi di programmazione funzionale, l'approccio idiomatico implica spesso la ricorsione. Questo sembra un po 'strano in Go e avrà prestazioni atroci. Detto questo, ecco una funzione di inversione di matrice ricorsiva (in un piccolo programma di test):

package main 

import (
    "fmt" 
) 

func main() { 
    myInts := []int{ 8, 6, 7, 5, 3, 0, 9 } 
    fmt.Printf("Ints %v reversed: %v\n", myInts, reverseInts(myInts)) 
} 

func reverseInts(input []int) []int { 
    if len(input) == 0 { 
     return input 
    } 
    return append(reverseInts(input[1:]), input[0]) 
} 

uscita:

Ints [8 6 7 5 3 0 9] reversed: [9 0 3 5 7 6 8] 

Ancora una volta, questo è per divertimento e non di produzione. Non solo è lento, ma sovrasta lo stack se l'elenco è troppo grande. Ho appena provato, e invertirà una lista di 1 milione int s ma si blocca su 10 milioni.

+1

Per i curiosi, c'è solo un TCO limitato in Go: http://stackoverflow.com/questions/12102675/tail-call-optimization-in-go – Lloeki

3

Prima di tutto, se si vuole invertire la matrice, fare come questo,

for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 { 
    a[i], a[j] = a[j], a[i] 
} 

Poi, guarda l'utilizzo di Reverse in golang.org

package main 

import (
    "fmt" 
    "sort" 
) 

func main() { 
    s := []int{5, 2, 6, 3, 1, 4} // unsorted 
    sort.Sort(sort.Reverse(sort.IntSlice(s))) 
    fmt.Println(s) 
} 

// output 
// [6 5 4 3 2 1] 

E guardare il dati Descrizione di Reverse e Sort

func Reverse(data Interface) Interface 
func Sort(data Interface) 

sort ordina. Effettua una chiamata a data.Len per determinare n e O (n * log (n)) chiamate a data.Less e data.Swap. L'ordinamento non è garantito per essere stabile.

Quindi, come sapete, Sort non è solo un algoritmo di ordinamento, è possibile visualizzare come una fabbrica, quando si utilizza Reverse solo restituire un algoritmo di ordinamento inverso, Sort sta solo facendo l'ordinamento.

+0

Probabilmente si dovrebbe solo iterare al punto centrale dell'array: https://play.golang.org/p/JeSApt80_k –

0

Per invertire una matrice in luogo, scorrere al suo punto centrale, e scambiare ogni elemento con il suo "elemento specchiante":

func main() { 
    xs := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} 
    itemCount := len(xs) 
    for i := 0; i < itemCount/2; i++ { 
     mirrorIdx := itemCount - i -1 
     xs[i], xs[mirrorIdx] = xs[mirrorIdx], xs[i] 
    } 
    fmt.Printf("xs: %v\n", xs) 
} 

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

1

o funzione fetta inversa più generica . Sarà panico se l'input non è una sezione.

//panic if s is not a slice 
func ReverseSlice(s interface{}) { 
    size := reflect.ValueOf(s).Len() 
    swap := reflect.Swapper(s) 
    for i, j := 0, size-1; i < j; i, j = i+1, j-1 { 
     swap(i, j) 
    } 
} 
1

Non capovolgerlo, lasciarlo come ora e poi solo iterarlo all'indietro.

+0

lol cosa? Non è consentita la retromarcia? – Zachscs

Problemi correlati