let numberSet = Set(1...11)
let divideSet = numberSet.map({ $0 / 10 })
//Error: Set does not have a member named map :(
Swift 1.2 supports Set()
for unordered collections, but map(_:)
doesn't seem to work on Sets, so i decide to get smart on my playground and tried:
let stringSet = Set(map(numberSet, { String($0)}))
println(stringSet)
stringSet = ["2", "11", "1", "8", "6", "4", "3", "9", "7", "10", "5]
This seemed to work. So I tried extending Set:
extension Set {
func map<U>(transform: (T) -> U) -> Set<U> {
return Set(Swift.map(self, transform)) }
}
Error: "couldn't find initialiser for Set(T) that accepts argument of type U"
And i think there is a good reason why it doesn’t work, like this example here:
let smarDividSet = Set(map(numberSet, {$0 / 2}))
println(smarDividSet)
smartDividSet = "[5, 0, 2, 4, 1, 3]”
//Somehow elements is the Set are going missing.
Any ideas on how to extend Set to use map(_:) reliably ?. Thank guys.
Update: Quite a lot changed with Swift 2 and 3. The generic
placeholder of Set
is now Element
instead of T
, and all
collections have a map()
method which returns an array.
There were also good arguments given about the problems of a Set -> Set
mapping (such as different elements mapping to the same result).
On the other hand, there may be a use-case for such a mapping,
so here is an update for Swift 3 (now using a different name).
extension Set {
func setmap<U>(transform: (Element) -> U) -> Set<U> {
return Set<U>(self.lazy.map(transform))
}
}
Example:
let numberSet = Set(1...11)
let divideSet = numberSet.setmap { $0 / 2 }
print(divideSet) // [5, 0, 2, 4, 1, 3]
(Old answer:) You were almost there. For some reason, the generic type of the returned set must be specified explicitly:
extension Set {
func map<U>(transform: (T) -> U) -> Set<U> {
return Set<U>(Swift.map(self, transform))
}
}
Example:
let numberSet = Set(1...11)
let divideSet = numberSet.map { $0 / 2 }
println(divideSet) // [5, 0, 2, 4, 1, 3]
The resulting set has less elements because the integer division
$0 / 2
truncates the quotient, e.g. both 4/2 and 5/2 map to
the same element 2. This does not happen with floating point division:
let floatdivideSet = numberSet.map { Double($0) / 2.0 }
println(floatdivideSet) // [4.0, 5.0, 4.5, 5.5, 2.0, 3.0, 3.5, 2.5, 1.5, 1.0, 0.5]
Another possible implementation is
extension Set {
func map<U>(transform: (T) -> U) -> Set<U> {
return Set<U>(lazy(self).map(transform))
}
}
Here lazy(self)
returns a LazyForwardCollection
which has
a map()
method and that returns a LazyForwardCollection
again.
The advantage might be that no intermediate array is created.