2012-02-12 13 views
28

Esiste un modo per controllare fette/mappe per la presenza di un valore?Vai: Aggiungi se univoco

Vorrei aggiungere un valore a una fetta solo se lo fa non esistono nella fetta.

Questo funziona, ma sembra prolisso. C'è un modo migliore per farlo?

orgSlice := []int{1, 2, 3} 
newSlice := []int{} 
newInt := 2 

newSlice = append(newSlice, newInt) 
for _, v := range orgSlice { 
    if v != newInt { 
     newSlice = append(newSlice, v) 
    } 
} 

newSlice == [2 1 3] 
+1

Ri: EDIT - è la stessa storia per qualsiasi tipo di chiave di mappa valida - quale stringa è. – zzzz

+1

Re: EDIT2 - se l'ordine dei valori in 'newSlice' non ha importanza E sarà usato/consumato usando un'istruzione di intervallo quindi la sua costruzione è ridondante - basta impostare le chiavi di 'set'. – zzzz

+0

@jnml Grazie per i vostri commenti. Sto memorizzando la lista di 'ints' in GAE datastore e allo scopo di interrogarla deve essere una slice (' [] int'). Questo requisito rende la mia tecnica iniziale la scelta migliore? Le liste saranno piccole. –

risposta

46

Il tuo approccio richiederebbe un tempo lineare per ogni inserimento. Un modo migliore sarebbe utilizzare uno map[int]struct{}. In alternativa, è possibile utilizzare anche uno map[int]bool o qualcosa di simile, ma lo struct{} vuoto presenta il vantaggio che non occupa spazio aggiuntivo. Pertanto, map[int]struct{} è una scelta popolare per un insieme di numeri interi.

Esempio:

set := make(map[int]struct{}) 
set[1] = struct{}{} 
set[2] = struct{}{} 
set[1] = struct{}{} 
// ... 

for key := range(set) { 
    fmt.Println(key) 
} 
// each value will be printed only once, in no particular order 


// you can use the ,ok idiom to check for existing keys 
if _, ok := set[1]; ok { 
    fmt.Println("element found") 
} else { 
    fmt.Println("element not found") 
} 
+0

Grazie per la risposta. Un paio di domande: come ricreeresti la fetta? C'è un modo per far funzionare questa strategia con le stringhe? Scusate se sono ovvi - sono nuovo per andare. –

+3

Userò solo la mappa durante il calcolo (perché ha un comportamento O (1) invece di O (n)). Successivamente, puoi creare una sezione e copiare ciascun valore dalla mappa. Gli elementi avranno un ordine casuale dopo quello, quindi potresti volerli ordinare.E puoi usare int, float, struct, string e array come chiavi di mappa (almeno in Go1). – tux21b

+0

Grazie in particolare per sottolineare che le strutture vuote non occupano spazio aggiuntivo. Non lo sapevo e avrei usato map [type] interface {} e avrei assegnato nil all'interfaccia. – user1943442

22

più efficiente è probabile che sia scorrere il fetta e aggiungendo se non lo trovate.

func AppendIfMissing(slice []int, i int) []int { 
    for _, ele := range slice { 
     if ele == i { 
      return slice 
     } 
    } 
    return append(slice, i) 
} 

È semplice ed evidente e sarà veloce per le piccole liste.

Inoltre, sarà sempre più veloce della tua attuale soluzione basata su mappa. La soluzione basata su mappe esegue iterazioni su tutta la sezione, a prescindere da cosa; questa soluzione ritorna immediatamente quando scopre che il nuovo valore è già presente. Entrambe le soluzioni confrontano gli elementi mentre eseguono l'iterazione. (Ogni affermazione di assegnazione di mappe esegue almeno un confronto con una chiave di mappa internamente.) Una mappa sarebbe utile solo se si riuscisse a mantenerla su molti inserimenti. Se lo ricostruisci su ogni inserimento, allora tutti i vantaggi sono persi.

Se è veramente necessario gestire in modo efficiente elenchi di grandi dimensioni, è consigliabile mantenere gli elenchi in ordine. (Sospetto che l'ordine non ti importi perché la tua prima soluzione è stata aggiunta all'inizio della lista e la tua ultima soluzione viene aggiunta alla fine.) Se mantieni sempre gli elenchi ordinati, puoi utilizzare la funzione sort.Search per fare inserimenti binari efficienti.

+8

"La soluzione basata su mappe itera su tutta la sezione, indipendentemente da cosa" - sei sicuro che questo è il modo in cui funzionano le hash-map? – Ottokar

+0

@Ottokar, si sbaglia? Molte persone hanno votato ma nessuna risposta è stata lasciata. –

+1

@FilipBartuzi In realtà, penso di aver frainteso il significato di questa affermazione. Le hash-maps ovviamente non eseguono iterazioni sugli elementi per trovare la chiave, ma la "soluzione basata sulla mappa" su "accoda a slice se unica" perde il suo vantaggio se dobbiamo convertire la slice in map e poi la mappa in slice . – Ottokar