2014-07-14 9 views
5

Ich möchte Elemente aus einer Sammlung in einer In-Place-Weise löschen. Betrachten Sie das folgende Snippet:An Ort und Stelle Löschen von Golang-Scheibenelementen

package main 

import "fmt" 

type Ints []int 

func (xs Ints) Filter() { 
    for i := 0; i < len(xs); i++ { 
     if xs[i]%2 == 0 { // Or some other filtering function 
      xs = append(xs[:i], xs[i+1:]...) 
     } 
     fmt.Printf("i %+v\n", i) 
     fmt.Printf("xs %+v\n", xs) 
    } 
} 

func main() { 
    a := Ints([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) 

    fmt.Printf("initial a %+v\n", a) 

    a.Filter() 

    fmt.Printf("final a %+v\n", a) 
} 

http://play.golang.org/p/1nL6Il2Gf1

Das überraschende Ergebnis ist: final a [1 3 5 7 9 10 10 10 10 10]

Ich frage mich, wie dies zu tun. Ich bin mir ziemlich sicher, dass der Empfänger ein Zeiger auf Ints sein muss. Aber das bringt den Code etwas durcheinander (Hinzufügen von *xs überall möglicherweise mit Klammern), aber noch wichtiger, es ergibt das gleiche Ergebnis.

Antwort

2

Ich würde es tun, indem Sie Elemente verschieben, dann die Größe ändern und einen Zeiger verwenden. Etwas wie dieses:

package main 

import "fmt" 

type Ints []int 

func (xs *Ints) Filter() { 
    filterPos := 0 
    for i := 0; i < len(*xs); i++ { 
     if (*xs)[i]%2 == 0 { // Or some other filtering function 
      (*xs)[filterPos] = (*xs)[i] 
     filterPos++ 
     } 
    } 
    (*xs) = (*xs)[:filterPos] 
} 

func main() { 
    a := Ints([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) 

    fmt.Printf("initial a %+v\n", a) 

    a.Filter() 

    fmt.Printf("final a %+v\n", a) 
} 
+1

Nur eine kleine Empfehlung, Verwendung '(* xs) = (* xs) [: filterPos: filterPos]' stattdessen die Scheibe und frei den zusätzlichen Speicher zu trimmen, könnte es ein anständiger sein Menge an Speicher mit größeren Objekten. – OneOfOne

+0

@ OneOfOne True, es hängt davon ab, ob Sie für Geschwindigkeit oder Speicher optimieren. Ich würde eigentlich nur ein neues Stück erstellen und alles unveränderlich halten, außer es wäre ein großer Teil des Gedächtnisses. –

+0

Richtig, hier ist, was ich meinte http://play.golang.org/p/FgeuFdr3-v – OneOfOne

1

Sie müssen Zeiger hier verwenden. Wenn Sie nicht möchten, dass * xs überall hinzugefügt wird, verwenden Sie einfach eine temporäre Variable, um alle Operationen auszuführen, und setzen Sie sie zurück. Hier ist der Code http://play.golang.org/p/eAFkV3Lwh6

1

Ihr Code war fast richtig.

Der erste Fehler ist, dass Sie vermeiden müssen, i++ zu tun, wenn Sie ein Element löschen, ansonsten überspringt das i++ das nächste, ungelesene Element. Deshalb habe ich es in die else Klausel geschrieben.

Der zweite Fehler ist, dass xs ist eine lokale Variable der Filter Funktion, wenn Sie also ändern, was er zeigt (mit xs = ...), der sich nicht ändert, was a Punkte innerhalb main. Sie können dieses Problem lösen, indem Sie es zu einem Zeiger machen (*xs, wie andere es geschrieben haben) oder indem Sie das neue gefilterte Segment zurückgeben, wie ich unten getan habe.

package main 

import "fmt" 

type Ints []int 

func (xs Ints) Filtered() Ints { 
    for i := 0; i < len(xs); { 
     if xs[i]%2 == 0 { 
      xs = append(xs[:i], xs[i+1:]...) 
     } else { 
      i++ 
     } 
    } 
    return xs 
} 

func main() { 
    a := Ints([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) 
    b := a.Filtered() 
    fmt.Println(b) 
} 

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

Verwandte Themen