2016-07-31 12 views
7

Ich habe ein [String:String] Wörterbuch. Ich möchte den Wert erhalten, der mit irgendeinem Schlüssel verbunden ist, der die Zeichenkette "S" enthält. Ordnung spielt keine Rolle.Finden Sie einen Schlüssel mit String in Swift-Wörterbuch

Das ist tod einfach: nur alle Schlüssel erhalten, iterieren, geben Sie die erste Übereinstimmung der Bedingung zurück.

JEDOCH möchte ich das mit einem schnellen-wie eleganten Ansatz tun. Etwas mit einem filter oder map funktioniert. Und das ist, wo ich verloren gehen ...

Antwort

9

Da Sie nur daran interessiert sind in jeder Einstimmungswert, können Sie verwenden die indexOf() Methode, um den ersten passenden Wörterbucheintrag zu finden. Dies funktioniert, weil ein Wörterbuch eine Sammlung von Schlüssel/Wert-Paaren ist.

Swift 2:

let dict = ["foo": "bar", "PQRS": "baz"] 
let searchTerm = "S" 

if let index = dict.indexOf({ (key, _) in key.containsString(searchTerm) }) { 
    let value = dict[index].1 
    print(value) 
} else { 
    print("no match") 
} 

Sobald ein passender Schlüssel gefunden wird, das Prädikat liefert true und die Aufzählung stoppt. Der index ist ein "Wörterbuchindex", der direkt zum Abrufen des entsprechenden Wörterbucheintrags verwendet werden kann.

Für Groß- und Kleinschreibung Schlüssel suchen, durch das Prädikat ersetzen

{ 
    (key, _) in key.rangeOfString(searchTerm, options: .CaseInsensitiveSearch) != nil 
} 

In Swift 3 Sie first(where:) verwenden können, das erste passende Element zu finden, das eine Wörterbuchsuche spart:

if let entry = dict.first(where: { (key, _) in key.contains(searchTerm) }) { 
    print(entry.value) 
} else { 
    print("no match") 
} 

Für eine Schlüsselsuche ohne Groß-/Kleinschreibung ersetzen Sie das Prädikat durch

+0

Wenn ich keine Groß-/Kleinschreibung brauche, weil ich weiß, dass Strings alle Großbuchstaben sind, kann ich key.contains() anstelle von key.range() verwenden oder ist key.range() schneller? – Adeline

+0

@Adeline: Ich denke nicht, dass es einen Unterschied macht, aber 'key.contains()' ist einfacher, also würde ich das verwenden. –

+0

Alle drei Antworten sind gültig, aber seine eine ist die schnellste. – Adeline

4

Sie filter verwenden können, contains und first zu finden "s":

Swift 2

if let key = yourDictionary.keys.filter({ $0.lowercaseString.characters.contains("s") }).first, let result = yourDictionary[key] { 
    print(result) 
} 

Swift 3

if let key = yourDictionary.keys.filter({ $0.lowercased().contains("s") }).first, let result = yourDictionary[key] { 
    print(result) 
} 

In einem Kommentar, @Hamish bietet diese hervorragende Alternative für Swift 3: statt

filter({ ... }).first 

können Sie verwenden

first(where: { ... }) 

Beispiel:

if let key = yourDictionary.keys.first(where: { $0.lowercased().contains("s") }), let result = yourDictionary[key] { 
    print(result) 
} 
+1

Beachten Sie, dass Sie in Swift 3 auch ['first (wo:)'] (http://swiftdoc.org/v3.0/protocol/Sequence/#func-first_) verwenden können, um dies zu tun. – Hamish

+0

@Hamish Dies ist eine ausgezeichnete Idee, danke. Wirst du es in einer Antwort verwenden, oder füge ich es zu meinem hinzu (mit Zuordnung natürlich)? – Moritz

+0

@EricD Es stört mich nicht :) Ich merke, dass Martin es auch in seiner Antwort verwendet hat (gruseliges Timing dort!), Also sehe ich keinen wirklichen Sinn darin, eine separate Antwort darauf zu geben. – Hamish

4

Sie können es mit flatMap und containsString:

Swift 2.x:

let dict = ["one": "1", "two": "2", "three": "3", "four": "4", "five": "5", "six": "6"] 

let results = dict.flatMap { (key, value) in key.lowercaseString.containsString("o") ? value : nil } 

print(results) 

Ausgang:

["4", "1", "2"] 
print(results.first ?? "Not found") 
4 

Oder wenn Sie lieben kryptischen Einzeiler:

let first = dict.flatMap { $0.lowercaseString.containsString("o") ? $1 : nil }.first ?? "Not found" 

Für Swift 3:

let dict = ["one": "1", "two": "2", "three": "3", "four": "4", "five": "5", "six": "6"] 

let results = dict.flatMap { (key, value) in key.lowercased().contains("o") ? value : nil } 

print(results) 
print(results.first ?? "Not Found") 

Oder wenn Sie kryptische Einzeiler lieben:

let first = dict.flatMap { $0.lowercased().contains("o") ? $1 : nil }.first ?? "Not Found" 
Verwandte Themen