2015-11-03 17 views
11

Angenommen, ich habe ein Array von AnyObject.Filtern eines Swift [AnyObject] Arrays nach Typ

let grabBag: [AnyObject] = [ "Tom", 4, "Dick", NSObject(), "Harry" ] 

und ich möchte es auf ein Array von Strings werfen, nur diejenigen Elemente, die das Extrahieren Strings tatsächlich. Ich würde erwarten, dies funktioniert:

let strings = grabBag.filter{ $0 is String } as! [String]  // 1 

aber es gibt den Fehler 'Bool' is not convertible to 'String'. Doch dies funktioniert:

let definitelyStrings = grabBag.filter{ $0 is String }   // 2 
let strings = definitelyStrings as! [String]     // 

Warum 2 Arbeit, wenn 1 nicht? Und gibt es eine einfachere (als 2) Art und Weise, die Elemente eines [AnyObject] zu einem beliebigen [T] zu extrahieren und zu gießen? Diese

+0

In Beispiel 2 brauchen Sie nicht die zweite Zeile: 'let strings = grabBag.filter {$ 0 ist String}' ist ausreichend. Kein erzwungenes Gießen. Man beweise es mit 'strings is [String]', was true zurückgibt – vadian

+2

@vadian 'let strings = grabBag.filter {$ 0 ist String}' '' 'AnyObject]' mit OPs 'grabBag' Array zurück, nicht' [String] '. – Moritz

+0

@EricD: Aber du kannst 'grabBag.filter {$ 0 ist String} .map {$ 0lowercaseString}' was normalerweise nicht mit '[AnyObject]' – vadian

Antwort

15

Es ist besser zu verwenden flatMap für einen schönen Einstrich:

let strings = grabBag.flatMap { $0 as? String } 

Jetzt ist strings vom Typ [String].

6

ist, was flatMap ist für:

let strings = grabBag.flatMap{ $0 as? String } 

Dieser einen Verschluss nimmt, die eine optionale zurückgibt; Wenn das optionale nicht-null ist, wird es zum Ergebnis hinzugefügt.

( Beachten Sie, dass dies nicht die Bedeutung von flatMap aus anderen Sprachen übereinstimmt, und nicht einmal die andere Bedeutung von flatMap in Swift entspricht. Ein besserer Name mapOptional oder mapSome gewesen wäre. Aber es ist noch Art von "Es bildet sich zu Optionals, dann flacht alle Nils ab." Rob Mayoff bemerkt, dass wenn Optionals SequenceTypes wären, was sie wahrscheinlich sein sollten, dies ein vernünftiger Name wäre.)

+1

Scala 'flatMap' arbeitet mit der' Option' in der gleichen Weise Swifts 'flatMap' arbeitet mit ihrer' Optional'. Aber Scala bekommt es "umsonst", weil Scala "Option" einen vollständigen Traversable-Collection-Typ hat (der entweder 0 oder 1 Elemente enthält). Leider entspricht Swifts 'Optional' (derzeit) nicht dem' SequenceType'. –

+0

@robmayoff Ich habe die Unterschrift von Scala falsch gelesen. Es ist 'flatMap [B] (f: (A) ⇒ GenTraversableOnce [B]): Liste [B]'. Ich dachte, es wäre 'flatMap [B] (f: (A) ⇒ Liste [Liste [B]]): Liste [B]'. OK; Ich werde das kaufen. –

3

Ich würde sagen, dass Test 1 Fehler ist eindeutig ein Compiler-Fehler. In der Tat stürzt es in der REPL:

Welcome to Apple Swift version 2.0 (700.1.100.2 700.1.74). Type :help for assistance. 
    1> import Foundation 
    2> let grabBag: [AnyObject] = [ "Tom", 4, "Dick", NSObject(), "Harry" ] 
grabBag: [AnyObject] = 5 values { 
    [0] = "Tom" 
    [1] = Int64(4) 
    [2] = "Dick" 
    [3] = { 
    isa = NSObject 
    } 
    [4] = "Harry" 
} 
    3> let strings = grabBag.filter { $0 is String } as! String 
strings: String = { 
    _core = { 
    _baseAddress = 
    _countAndFlags = 
    _owner = <extracting data from value failed> 

    } 
} 
Execution interrupted. Enter Swift code to recover and continue. 
Enter LLDB commands to investigate (type :help for assistance.) 
4> :bt 
* thread #1: tid = 0x501bac, 0x00000001005c41f4 $__lldb_expr12`main + 420 at repl.swift:3, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) 
    * frame #0: 0x00000001005c41f4 $__lldb_expr12`main + 420 at repl.swift:3 
    frame #1: 0x0000000100001420 repl_swift`_mh_execute_header + 5152 
    frame #2: 0x00007fff8dd725c9 libdyld.dylib`start + 1 
    frame #3: 0x00007fff8dd725c9 libdyld.dylib`start + 1 

Wie auch immer, als Rob Napier auch beantwortet, grabBag.flatMap { $0 as? String } ist kürzer und vielleicht einfacher.

Verwandte Themen