2017-07-23 4 views
1

J'essaie d'apprendre Go, voici donc ma fonction très simple pour supprimer les doublons adjacents de la tranche pour l'exercice du livre par Donovan & Kernighan.
Voici le code: https://play.golang.org/p/avHc1ixfckModifier le contenu de la tranche et la capacité dans une fonction in-place

package main 
import "fmt" 

func main() { 
    a := []int{0, 1, 1, 3, 3, 3} 
    removeDup(a) 
    fmt.Println(a) 
} 

func removeDup(s []int) { 
    n := len(s) 
    tmp := make([]int, 0, n) 
    tmp = append(tmp, s[0]) 
    j := 1 
    for i := 1; i < n; i++ { 
     if s[i] != s[i-1] { 
      tmp = append(tmp, s[i]) 
      j++ 
     } 
    } 
    s = s[:len(tmp)] 
    copy(s, tmp) 
} 

Il doit imprimer [0 1 3] - et j'ai vérifié, en fait tmp à la fin de la fonction qu'il a forme désirée. Cependant, le résultat est [0 1 3 3 3 3]. Je suppose qu'il y a quelque chose avec la fonction copy. Puis-je en quelque sorte remplacer la tranche d'entrée s par la temp ou la découper à la longueur désirée?

+0

'removeDup' devrait retourner la nouvelle tranche. – zerkms

Répondre

4

Option 1

Retour d'une nouvelle tranche comme suggéré par @zerkms.
https://play.golang.org/p/uGJiD3WApS

package main 
import "fmt" 

func main() { 
    a := []int{0, 1, 1, 3, 3, 3} 
    a = removeDup(a) 
    fmt.Println(a) 
} 

func removeDup(s []int) []int { 
    n := len(s) 
    tmp := make([]int, 0, n) 
    tmp = append(tmp, s[0]) 
    for i := 1; i < n; i++ { 
     if s[i] != s[i-1] { 
      tmp = append(tmp, s[i]) 
     } 
    } 
    return tmp 
} 

Option 2
utilisation des pointeurs pour passage par référence.
La même chose en vigueur que celle de l'option1.

https://play.golang.org/p/80bE5Qkuuj

package main 

import "fmt" 

func main() { 
    a := []int{0, 1, 1, 3, 3, 3} 
    removeDup(&a) 
    fmt.Println(a) 
} 

func removeDup(sp *[]int) { 
    s := *sp 
    n := len(s) 
    tmp := make([]int, 0, n) 
    tmp = append(tmp, s[0]) 
    for i := 1; i < n; i++ { 
     if s[i] != s[i-1] { 
      tmp = append(tmp, s[i]) 
     } 
    } 
    *sp = tmp 
} 

Aussi, reportez-vous à suivre SO fil: Does Go have no real way to shrink a slice? Is that an issue?

+0

Je savais que retourner une nouvelle tranche et l'assigner à une tranche précédemment déclarée ferait l'affaire, mais je voulais le faire en fonction. Les pointeurs semblent être la solution désirée, merci! J'ai l'arrière-plan Python, ne peut toujours pas s'habituer à l'aide de pointeurs. –

+0

Vous les obtiendrez finalement et vous vous sentirez vraiment bête quand vous réaliserez que c'est un concept impressionnant (un peu) dans la programmation. C'est ce que j'ai ressenti! :) – hbagdi

0

est ici deux autres façons légèrement différentes pour obtenir ce que vous voulez en utilisant des ensembles et des types nommés. Ce qu'il y a de sympa avec les types nommés, c'est que vous pouvez créer des interfaces autour d'eux et aider à la lisibilité de beaucoup de code.

package main 

import "fmt" 

func main() { 
    // returning a list 
    a := []int{0, 1, 1, 3, 3, 3} 
    clean := removeDup(a) 
    fmt.Println(clean) 
    // creating and using a named type 
    nA := &newArrType{0, 1, 1, 3, 3, 3} 
    nA.removeDup2() 
    fmt.Println(nA) 

    // or... casting your orginal array to the named type 
    nB := newArrType(a) 
    nB.removeDup2() 
    fmt.Println(nB) 
} 

// using a set 
// order is not kept, but a set is returned 
func removeDup(s []int) (newArr []int) { 
    set := make(map[int]struct{}) 
    for _, n := range s { 
     set[n] = struct{}{} 
    } 
    newArr = make([]int, 0, len(set)) 
    for k := range set { 
     newArr = append(newArr, k) 
    } 
    return 
} 

// using named a typed 
type newArrType []int 

func (a *newArrType) removeDup2() { 
    x := *a 
    for i := range x { 
     f := i + 1 
     if f < len(x) { 
      if x[i] == x[f] { 
       x = x[:f+copy(x[f:], x[f+1:])] 
      } 
     } 
    } 
    // check the last 2 indexes 
    if x[len(x)-2] == x[len(x)-1] { 
     x = x[:len(x)-1+copy(x[len(x)-1:], x[len(x)-1+1:])] 
    } 
    *a = x 
} 
+0

Juste pour le plaisir de la curiosité, je veux quelques commentaires sur la pensée suivante - Bien que ce soit une solution parfaitement acceptable pour moi car il fait le OOPSy, n'est-ce pas trop pour un tel cas? Serait-il logique de ne pas avoir la méthode 'removeDup' associée à un type, mais de le garder dans un autre? – hbagdi

+0

Il pourrait être exagéré pour un si petit exemple, mais si c'était un projet énorme, ou si vous vouliez l'utiliser simultanément, ou removeDups nécessaire pour opérer sur quelque chose de plus générique comme une interface (nous espérons), ou removeDups est seulement une opération sur une chaîne d'opérations qui opère sur un pointeur. Sur le plus grand projet, la séparation des types est plus facile à gérer. La concurrence peut être gérée en étendant puis le type nommé était les verrous et les sémaphores. Les opérations de pointeur chaînées sont plus faciles à écrire et peut-être à lire. Voir ici aussi https://hunterloftis.github.io/2017/07/12/renamed-types/ – reticentroot

+0

Bien, cela a du sens, merci pour la réponse détaillée. – hbagdi