Swift Set() 的 map(_:) 扩展?

Swift map(_:) extension for Set() ?

  let numberSet = Set(1...11)
  let divideSet = numberSet.map({  [=11=] / 10 }) 
  //Error: Set does not have a member named map   :(

Swift 1.2 支持 Set() 用于无序集合,但 map(_:) 似乎不适用于集合,所以我决定在我的操场上变聪明并尝试:

 let stringSet = Set(map(numberSet, { String([=12=])}))
 println(stringSet)
 stringSet =  ["2", "11", "1", "8", "6", "4", "3", "9", "7", "10", "5]

这似乎有效。 所以我尝试扩展 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"

而且我认为它不起作用是有充分理由的,就像这里的这个例子:

   let smarDividSet = Set(map(numberSet, {[=14=] / 2})) 
   println(smarDividSet)
   smartDividSet = "[5, 0, 2, 4, 1, 3]” 
  //Somehow elements is the Set are going missing.

关于如何扩展 Set 以可靠地使用 map(_:) 有什么想法吗?。 谢谢大家。

更新: Swift 2 和 3 发生了很多变化。通用的 Set 的占位符现在是 Element 而不是 T,所有 集合有一个 map() 方法,其中 returns 一个 数组。

关于 Set -> Set 映射的问题(例如不同的元素映射到相同的结果)也给出了很好的论据。 另一方面,这种映射可能有一个用例, 所以这是 Swift 3 的更新(现在使用不同的名称)。

extension Set {
    func setmap<U>(transform: (Element) -> U) -> Set<U> {
        return Set<U>(self.lazy.map(transform))
    }
}

示例:

let numberSet = Set(1...11)
let divideSet = numberSet.setmap { [=11=] / 2 }
print(divideSet) // [5, 0, 2, 4, 1, 3]

(旧答案:)你快到了。出于某种原因, 必须明确指定返回的集合:

extension Set {
    func map<U>(transform: (T) -> U) -> Set<U> {
        return Set<U>(Swift.map(self, transform))
    }
}

示例:

let numberSet = Set(1...11)

let divideSet = numberSet.map { [=13=] / 2 }
println(divideSet) // [5, 0, 2, 4, 1, 3]

结果集的元素较少,因为整数除法 [=21=] / 2 截断 商,例如4/2 和 5/2 都映射到 相同的元素 2。浮点除法不会发生这种情况:

let floatdivideSet = numberSet.map { Double([=14=]) / 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]

另一个可能的实现是

extension Set {
    func map<U>(transform: (T) -> U) -> Set<U> {
        return Set<U>(lazy(self).map(transform))
    }
}

这里 lazy(self) returns 一个 LazyForwardCollection 其中有 map() 方法和 returns 又是 LazyForwardCollection。 优点可能是没有创建中间数组。

Set.map(_:) 的问题与 Dictionary.map(_:) 相同,他们没有在 Swift 模块(标准库)中实现它,因为实际上 没有正确的方法 来实现它。原因是:mapping 不仅仅是枚举(您可以对 for-in 中的任何 SequenceType 进行枚举),而是将每个值转换(使用参数闭包)到另一个值。所以你会期望结果中包含所有 transform(element),但是你猜怎么着,如果值相同,它们就会崩溃(对于 Dictionary,只有键以这种方式表现)。

例如(与建议的实施) Set([1, 2, 3, 4, 5]).map { 1 }.count == 1

这也是为什么 Swift.map returns 一个 Array 而不是相同类型的 SequenceType/CollectionType 作为 source 参数传递的原因.

稍稍题外话,Dictionary(如前所述)在键值(基本上是 Set)上有同样的问题,所以任何 map Set<K>Set<(K, V)> 不能确保一致的映射,但仅更改值就可以了。它不会是真正的 map,因为 Dictionarys 是元组的集合,而不仅仅是值。所以可能有类似于 mapValues 的东西是正确的,但在集合中仍然不是真正的 map

TL;DR

map 确实很有用,但要小心你实际在做什么,因为你不能 真的 做一个 mapSetSet.

从 Swift 2.0 开始,CollectionType 协议(由 Set 实现)有一个 map 方法。

我为 Set 做了扩展:

extension Set {

    /// Map, but for a `Set`.
    /// - Parameter transform: The transform to apply to each element.
    func map<T>(_ transform: (Element) throws -> T) rethrows -> Set<T> {
        var tempSet = Set<T>()

        try forEach {
            tempSet.insert(try transform([=10=]))
        }

        return tempSet
    }
}

例如:

let someSet: Set<Int> = [1, 3, 5, 7]
print(someSet.map { [=11=] + 1 })

// Prints:  [2, 6, 8, 4]