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

Ble*_*pes 13 swift swift-extensions

  let numberSet = Set(1...11)
  let divideSet = numberSet.map({  $0 / 10 }) 
  //Error: Set does not have a member named map   :(
Run Code Online (Sandbox Code Playgroud)

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

 let stringSet = Set(map(numberSet, { String($0)}))
 println(stringSet)
 stringSet =  ["2", "11", "1", "8", "6", "4", "3", "9", "7", "10", "5]
Run Code Online (Sandbox Code Playgroud)

这似乎有效.所以我尝试扩展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"
Run Code Online (Sandbox Code Playgroud)

我认为它有一个很好的理由,它不起作用,就像这个例子:

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

关于如何将Set扩展为可靠地使用map(_ :)的任何想法?谢谢你们.

Mar*_*n R 14

更新:相当多的与斯威夫特2和3的通用占位改变Set,现在Element不是T,所有的收藏有一个map()返回的方法数组.

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

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

例:

let numberSet = Set(1...11)
let divideSet = numberSet.setmap { $0 / 2 }
print(divideSet) // [5, 0, 2, 4, 1, 3]
Run Code Online (Sandbox Code Playgroud)

(老答案:)你几乎就在那里.由于某种原因,必须明确指定返回集的泛型类型:

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

例:

let numberSet = Set(1...11)

let divideSet = numberSet.map { $0 / 2 }
println(divideSet) // [5, 0, 2, 4, 1, 3]
Run Code Online (Sandbox Code Playgroud)

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

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]
Run Code Online (Sandbox Code Playgroud)

另一种可能的实现是

extension Set {
    func map<U>(transform: (T) -> U) -> Set<U> {
        return Set<U>(lazy(self).map(transform))
    }
}
Run Code Online (Sandbox Code Playgroud)

这里lazy(self)返回一个LazyForwardCollectionmap()方法并LazyForwardCollection再次返回的方法.优点可能是没有创建中间数组.


DeF*_*enZ 7

问题Set.map(_:)是相同的Dictionary.map(_:),并且他们没有在Swift模块(标准库)中实现它,因为实际上没有正确的方法来实现它.原因是:mapping不只是枚举(你可以用a中的任何SequenceType一个来做for-in),但它正在将每个值转换(使用参数闭包)到另一个值.所以你会期望结果会包含所有transform(element)内容,但是猜猜看,如果值相同则会崩溃(对于Dictionarys,只有键的行为是这样的).

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

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

稍微偏离,Dictionary(如前所述)在键值上有相同的问题(基本上是a Set),所以任何mapSet<K>Set<(K, V)>不能确保一致的映射,但只改变值的是好.这不是真的,map因为Dictionarys是元组的集合,而不仅仅是价值.所以可能有类似的东西mapValues是正确的,但map在集合上仍然不是真的.

TL; DR

map真的是有用的,但要小心你实际上在做什么,因为你不能真正mapSetSet.

  • 抱歉,我打错了评论,它让我不能再编辑了。我再说一遍:恐怕我不能同意。这正是 Haskell 中 map on set 的工作方式,在我看来,这很自然。当然,这是将数据类型上的函数提升到数学中该类型的一组元素上的函数的常用方法。如果 f 是从 X 到 Y 的函数,则定义 f 从 P(X) 到 P(Y)(P 是幂集)由 fS) = {f(s) | s 在 S}。此外,由于集合是无序的,而列表是有序的,因此很难看出如何使用您认为是自然的构造。 (2认同)