web-dev-qa-db-ja.com

配列を縮小してSwiftに設定します

オブジェクトの配列をSwiftのセットに削減しようとしていますが、これが私のコードです。

objects.reduce(Set<String>()) { $0.insert($1.URL) }

ただし、エラーが発生します。

Type of expression is ambiguous without more context.

URLのタイプは間違いなくStringであるため、問題が何であるかはわかりません。何か案は?

59
Banana

配列をセットに入れるために配列を減らす必要はありません。配列let objectSet = Set(objects.map { $0.URL })を使用してセットを作成するだけです。

99
NRitH

Swift 5.1では、問題を解決するために次の3つの例のいずれかを使用できます。


#1。 Arrayの-​​ map(_:) メソッドとSetの-​​ init(_:) 初期化子の使用

最も単純なケースでは、初期配列をurls(String)の配列にマッピングし、その配列からセットを作成できます。以下のコードのプレイグラウンドは、その方法を示しています。

struct MyObject {
    let url: String
}

let objectArray = [
    MyObject(url: "mozilla.org"),
    MyObject(url: "gnu.org"),
    MyObject(url: "git-scm.com")
]

let urlArray = objectArray.map({ $0.url })
let urlSet = Set(urlArray)
dump(urlSet)
// ▿ 3 members
//   - "git-scm.com"
//   - "mozilla.org"
//   - "gnu.org"

#2。 Arrayの-​​ reduce(into:_:) メソッドを使用する

struct MyObject {
    let url: String
}

let objectArray = [
    MyObject(url: "mozilla.org"),
    MyObject(url: "gnu.org"),
    MyObject(url: "git-scm.com")
]

let urlSet = objectArray.reduce(into: Set<String>(), { (urls, object) in
    urls.insert(object.url)
})
dump(urlSet)
// ▿ 3 members
//   - "git-scm.com"
//   - "mozilla.org"
//   - "gnu.org"

別の方法として、Arrayの-​​ reduce(_:_:) メソッドを使用できます。

struct MyObject {
    let url: String
}

let objectArray = [
    MyObject(url: "mozilla.org"),
    MyObject(url: "gnu.org"),
    MyObject(url: "git-scm.com")
]

let urlSet = objectArray.reduce(Set<String>(), { (partialSet, object) in
    var urls = partialSet
    urls.insert(object.url)
    return urls
})
dump(urlSet)
// ▿ 3 members
//   - "git-scm.com"
//   - "mozilla.org"
//   - "gnu.org"

#3。 Array拡張機能を使用する

必要に応じて、mapToSetクロージャーパラメーターを受け取り、Arrayを返すtransformSetメソッドを作成できます。コードの下のプレイグラウンドは、その使用方法を示しています。

extension Array {

    func mapToSet<T: Hashable>(_ transform: (Element) -> T) -> Set<T> {
        var result = Set<T>()
        for item in self {
            result.insert(transform(item))
        }
        return result
    }

}

struct MyObject {
    let url: String
}

let objectArray = [
    MyObject(url: "mozilla.org"),
    MyObject(url: "gnu.org"),
    MyObject(url: "git-scm.com")
]

let urlSet = objectArray.mapToSet({ $0.url })
dump(urlSet)
// ▿ 3 members
//   - "git-scm.com"
//   - "mozilla.org"
//   - "gnu.org"
6
Imanou Petit

reduce()メソッドは、戻り値結合値であるクロージャーを期待しますが、Set値のinsert()メソッドは何も返さず、代わりに既存の要素に新しい要素を挿入しますセットする。

機能させるには、次のようなことをする必要があります。

objects.reduce(Set<String>()) {
    $0.union(CollectionOfOne($1.URL))
}

しかし、上記は少し不必要な複雑さです。大きな配列がある場合、Swiftがobjectsのすべての要素を処理している間に、非常に多くのセットが作成されることになります。 @NRitHのアドバイスに従い、map()を使用すると、結果セットが一度に作成されます。

5
Anton Bronnikov

オブジェクトのURLが厳密に型指定されたStringである場合、新しいSet<String>オブジェクトを作成し、マップされた配列を持つセットでunionInPlaceを使用できます。

var mySet = Set<String>()
mySet.unionInPlace(objects.map { $0.URL as String })
1
JAL