web-dev-qa-db-ja.com

Swiftの配列からnilsをフィルタリングする拡張機能を作成する

私は、オプションのTの配列を非オプションのTの配列に変換できるようにする拡張機能をArrayに書き込もうとしています。

例えばこれは、次のような無料の関数として書くことができます。

func removeAllNils(array: [T?]) -> [T] {
    return array
        .filter({ $0 != nil })   // remove nils, still a [T?]
        .map({ $0! })            // convert each element from a T? to a T
}

しかし、これを拡張機能として機能させることはできません。拡張機能はオプション値の配列にのみ適用されることをコンパイラに伝えようとしています。これは私がこれまでに持っているものです:

extension Array {
    func filterNils<U, T: Optional<U>>() -> [U] {
        return filter({ $0 != nil }).map({ $0! })
    }
}

(コンパイルしません!)

46
Javawag

汎用の構造体またはクラスに定義されている型を制限することはできません。配列はどの型でも機能するように設計されているため、型のサブセットで機能するメソッドを追加することはできません。型制約は、ジェネリック型を宣言するときにのみ指定できます

必要なものを達成する唯一の方法は、グローバル関数または静的メソッドを作成することです-後者の場合:

extension Array {
    static func filterNils(array: [T?]) -> [T] {
        return array.filter { $0 != nil }.map { $0! }
    }
}

var array:[Int?] = [1, nil, 2, 3, nil]

Array.filterNils(array)

または、単にcompactMap(以前はflatMap)を使用します。これは、すべてのnil値を削除するために使用できます。

[1, 2, nil, 4].compactMap { $0 } // Returns [1, 2, 4]
42
Antonio

Swift 2.0では、配列からnil値をフィルタリングするために独自の拡張機能を記述する必要はありません。配列を平坦化し、nilをフィルタリングするflatMapを使用できます。

let optionals : [String?] = ["a", "b", nil, "d"]
let nonOptionals = optionals.flatMap{$0}
print(nonOptionals)

プリント:

[a, b, d]

注意:

2つのflatMap関数があります。

80

スイフト4

Swift 4を使用できるほど幸運なら、compactMapを使用してnil値を除外できます。

array = array.compactMap { $0 }

例えば。

let array = [1, 2, nil, 4]
let nonNilArray = array.compactMap { $0 }

print(nonNilArray)
// [1, 2, 4]
11
Adam Wareing

Swift 2.0)以降、where句を使用して、タイプのサブセットに対して機能するメソッドを追加することができます。この Appleフォーラムスレッド これは、配列のnil値を除外するために使用できます。クレジットは@nnnnnnnnと@SteveMcQwarkに割り当てられます。

where句はまだジェネリックをサポートしていないため(Optional<T>)、プロトコルを介した回避策が必要です。

protocol OptionalType {  
    typealias T  
    func intoOptional() -> T?  
}  

extension Optional : OptionalType {  
    func intoOptional() -> T? {  
        return self.flatMap {$0}  
    }  
}  

extension SequenceType where Generator.Element: OptionalType {  
    func flatten() -> [Generator.Element.T] {  
        return self.map { $0.intoOptional() }  
            .filter { $0 != nil }  
            .map { $0! }  
    }  
}  

let mixed: [AnyObject?] = [1, "", nil, 3, nil, 4]  
let nonnils = mixed.flatten()    // 1, "", 3, 4  
11
fabb

スイフト4

これはSwift 4:

protocol OptionalType {
    associatedtype Wrapped
    var optional: Wrapped? { get }
}

extension Optional: OptionalType {
    var optional: Wrapped? { return self }
}

extension Sequence where Iterator.Element: OptionalType {
    func removeNils() -> [Iterator.Element.Wrapped] {
        return self.flatMap { $0.optional }
    }
}

テスト:

class UtilitiesTests: XCTestCase {

    func testRemoveNils() {
        let optionalString: String? = nil
        let strings: [String?] = ["Foo", optionalString, "Bar", optionalString, "Baz"]
        XCTAssert(strings.count == 5)
        XCTAssert(strings.removeNils().count == 3)
        let integers: [Int?] = [2, nil, 4, nil, nil, 5]
        XCTAssert(integers.count == 6)
        XCTAssert(integers.removeNils().count == 3)
    }
}
5
Sajjon