2014-12-23 17 views
40

Sto costruendo un'app per iOS con swift e ho bisogno di ottenere tutti i valori univoci dell'array di stringhe.Valori univoci dell'array in swift

Ho letto i documenti dello sviluppatore Apple ma non sembra avere una funzione per questo.

Qualcuno può darmi un suggerimento?

+2

Cerca in NSSet o NSOrderedSet. – rdelmar

+0

Io uso il dollaro. '$ .uniq (array)' https://github.com/ankurp/Dollar#uniq---uniq –

risposta

1

Utilizzare un dizionario come var unique = [<yourtype>:Bool]() e immettere valori come unique[<array value>] = true in un ciclo. Ora unique.keys ha ciò di cui hai bisogno.

33

Non c'è una funzione per fare questo nella libreria standard Swift, ma si potrebbe scrivere uno:

extension Sequence where Iterator.Element: Hashable { 
    func unique() -> [Iterator.Element] { 
     var seen: [Iterator.Element: Bool] = [:] 
     return self.filter { seen.updateValue(true, forKey: $0) == nil } 
    } 
} 

let a = ["four","one", "two", "one", "three","four", "four"] 
a.unique // ["four", "one", "two", "three"] 

Questo ha lo svantaggio di richiedere il contenuto della sequenza da hashable, non solo equatable , ma poi di nuovo le cose più equabili sono, comprese le stringhe.

Conserva anche l'ordinamento originale a differenza, ad esempio, inserendo il contenuto in un dizionario o in un set e quindi ripristinandoli di nuovo.

+0

C'è un errore? 'Uso di identificatore non risolto 'seq'' –

+0

Ah, quindi c'è, dovrebbe essere' filter (source) ' –

+0

Per la mia applicazione, questo metodo è almeno ~ 3 volte più veloce di distinto. –

89

Un modo è quello di utilizzare un set:

let array = ["one", "one", "two", "two", "three", "three"] 
let unique = Array(Set(array)) 
// ["one", "two", "three"] 

Si potrebbe anche creare un'estensione che filtra attraverso la matrice più esplicitamente:

extension Array where Element : Equatable { 
    var unique: [Element] { 
     var uniqueValues: [Element] = [] 
     forEach { item in 
      if !uniqueValues.contains(item) { 
       uniqueValues += [item] 
      } 
     } 
     return uniqueValues 
    } 
} 

NOTA

La matrice unica sarà in un ordine non specificato e potrebbe essere necessario ordinarlo. A volte è meglio farlo da soli enumerando, potresti scrivere un'estensione.

Potrebbe essere buono per fare un prolungamento (Swift 2):

extension Array where Element : Hashable { 
    var unique: [Element] { 
     return Array(Set(self)) 
    } 
} 

Probabilmente ci sono modi più ottimizzato per fare ciò che si vuole, ma in questo modo è semplice e veloce.

+2

Il primo esempio è pulito e semplice. Funziona con Swift 3. Grazie! – tracicot

+0

'Array (Set())' funziona anche in Swift 4. Ottima soluzione. Grazie. – Annjawn

3

Non so di un modo integrato. Questa funzione generica lo farebbe:

func distinct<S: SequenceType, E: Equatable where E==S.Generator.Element>(source: S) -> [E] 
{ 
    var unique = [E]() 

    for item in source 
    { 
     if !contains(unique, item) 
     { 
      unique.append(item) 
     } 
    } 
    return unique 
} 

Il rovescio della medaglia è che questa soluzione viene eseguito in O (n).

+0

'contains' viene eseguito in O (n) quindi questa soluzione viene eseguita in un tempo quadratico (sebbene abbia il vantaggio di non richiedere che gli elementi siano lavabili). –

+0

@AirspeedVelocity Sì, questo è un buon punto. E essere lavabile normalmente non sarà un problema come quello che hai indicato nella tua soluzione. Ciò nonostante è una soluzione alternativa, seppur più lenta, se dover essere lavabile è un rompicapo. Preferisco la tua soluzione, ma penso che terrò questa posizione per questo motivo. –

+0

Sovraccarico significa che è possibile implementare entrambi, e il migliore verrà scelto! (Dato che il metodo Hashable è conforme a Equitable, quindi è più specifico, la risoluzione di sovraccarico lo preferirà :) –

Problemi correlati