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

时间:2015-03-17 19:23:01

标签: swift swift-extensions

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

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]

这似乎有效。 所以我尝试扩展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, {$0 / 2})) 
   println(smarDividSet)
   smartDividSet = "[5, 0, 2, 4, 1, 3]” 
  //Somehow elements is the Set are going missing.

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

4 个答案:

答案 0 :(得分:13)

更新:使用Swift 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))
    }
}

示例:

let numberSet = Set(1...11)
let divideSet = numberSet.setmap { $0 / 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 { $0 / 2 }
println(divideSet) // [5, 0, 2, 4, 1, 3]

由于整数除法,结果集的元素较少 $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]

另一种可能的实现是

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

此处lazy(self)会返回LazyForwardCollection 一个map()方法,并再次返回LazyForwardCollection。 优点可能是没有创建中间数组。

答案 1 :(得分:7)

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

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

这也是为什么Swift.map返回Array而不是同一类型的SequenceType / CollectionType作为source参数传递的原因。< / p>

稍微偏离,Dictionary(如前所述)在键值上存在相同的问题(基本上是Set),因此任何map都可以在{ {1}}或Set<K>没有确保一致的映射,但只更改值的那个就没问题了。它不会是真正的Set<(K, V)>,因为map是元组的集合,而不仅仅是值。因此可能会有类似于Dictionary的内容,这些内容是正确的,但在集合上仍然不是真正的mapValues

TL; DR

map非常有用,但要注意你实际做的事情,因为你不能真的< / em>从mapmap执行Set

答案 2 :(得分:1)

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

答案 3 :(得分:0)

我为groupId作了扩展:

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($0))
        }

        return tempSet
    }
}