Ich versuche, ein Array von Objekten auf eine Menge in Swift zu reduzieren, und dies ist mein Code:
objects.reduce(Set<String>()) { $0.insert($1.URL) }
Ich erhalte jedoch eine Fehlermeldung:
Type of expression is ambiguous without more context.
Ich verstehe nicht, was das Problem ist, da der Typ der URL definitiv String ist. Irgendwelche Ideen?
func reduce<T>(_ initial: T, @noescape combine combine: (T, Self.Generator.Element) throws -> T) rethrows -> T
, was Sie nicht übergeben.Antworten:
Sie müssen ein Array nicht verkleinern, um es in einen Satz zu integrieren. Erstellen Sie einfach das Set mit einem Array :
let objectSet = Set(objects.map { $0.URL })
.quelle
let objectSet = Set(objects.map { $0.URL })
.Mit Swift 5.1 können Sie eines der drei folgenden Beispiele verwenden, um Ihr Problem zu lösen.
# 1. Verwenden
Array
dermap(_:)
Methode undSet
desinit(_:)
InitialisierersIm einfachsten Fall können Sie Ihr ursprüngliches Array einem Array von
url
s (String
) zuordnen und dann aus diesem Array einen Satz erstellen. Der folgende Code für den Spielplatz zeigt, wie es geht: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. Mit
Array
derreduce(into:_:)
Methode vonstruct 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"
Als Alternative, können Sie
Array
‚s -reduce(_:_:)
Methode: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. Verwenden einer
Array
ErweiterungBei Bedarf können Sie eine
mapToSet
Methode erstellenArray
, die einentransform
Abschlussparameter verwendet und a zurückgibtSet
. Der folgende Code für den Spielplatz zeigt, wie er verwendet wird: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"
quelle
reduce()
Die Methode erwartet einen Abschluss, der einen kombinierten Wert zurückgibt , während dieinsert()
WertmethodenSet
nichts zurückgeben, sondern stattdessen ein neues Element in die vorhandene Menge einfügen.Damit es funktioniert, müssten Sie Folgendes tun:
objects.reduce(Set<String>()) { $0.union(CollectionOfOne($1.URL)) }
Aber das Obige ist eine unnötige Komplikation. Wenn Sie ein großes Array haben, bedeutet dies, dass eine ganze Reihe von ständig wachsenden Sets erstellt werden müssen, während Swift alle Elemente von durchläuft
objects
. Befolgen Sie besser die Ratschläge von @NRitH und verwenden Sie diese,map()
da dies einen resultierenden Satz auf einmal ergeben würde.quelle
Wenn es sich
URL
bei Ihrem Objekt um ein stark typisiertes Objekt handeltString
, können Sie ein neuesSet<String>
Objekt erstellen undunionInPlace
am Set mit dem zugeordneten Array verwenden:var mySet = Set<String>() mySet.unionInPlace(objects.map { $0.URL as String })
quelle