Расширение Swift map(:) для Set()?
let numberSet = Set(1...11)
let divideSet = numberSet.map({ / 10 })
//Error: Set does not have a member named map :(
Swift 1.2 поддерживает Set()
для неупорядоченных коллекций, но map(_:)
похоже, не работает на множествах, поэтому я решил поумнеть на своей игровой площадке и попытался:
let stringSet = Set(map(numberSet, { String()}))
println(stringSet)
stringSet = ["2", "11", "1", "8", "6", "4", "3", "9", "7", "10", "5]
похоже, это сработало. Поэтому я попытался расширить набор:
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, { / 2}))
println(smarDividSet)
smartDividSet = "[5, 0, 2, 4, 1, 3]”
//Somehow elements is the Set are going missing.
любые идеи о том, как расширить набор для использования map(_:) надежно ?. Спасибо ребята.
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 { / 2 }
println(divideSet) // [5, 0, 2, 4, 1, 3]
результирующий набор имеет меньше элементов, потому что целочисленное деление
/ 2
усекает коэффициент, например, 4/2 и 5/2 сопоставляются с
один и тот же элемент 2. Это не происходит с делением с плавающей запятой:
let floatdivideSet = numberSet.map { Double() / 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
снова.
Преимущество может заключаться в том, что промежуточный массив не создается.
обновление: довольно много изменилось с Swift 2 и 3. Непатентованное средство
буква Set
теперь Element
вместо T
и все
сборники have a 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 { / 2 }
print(divideSet) // [5, 0, 2, 4, 1, 3]
вопрос с Set.map(_:)
то же самое с Dictionary.map(_:)
, и они не реализовали его в Swift
модуль (стандартная библиотека), потому что на самом деле не правильно для его реализации. Причина: map
ping не просто перечисляет (что вы можете сделать с любым SequenceType
на for-in
), но он преобразует (с закрытием аргумента) каждое значение в другое. Таким образом, вы ожидаете, что результат будет иметь все transform(element)
в нем, но думаю, что, если значения же они рушатся (ибо Dictionary
s только ключи ведут себя таким образом).
например, (с предлагаемой реализации)
Set([1, 2, 3, 4, 5]).map { 1 }.count == 1
вот почему Swift.map
возвращает Array
и не тот же тип SequenceType
/CollectionType
прошло как , хотя с Dictionary
С коллекции кортежей, а не только значение. Таким образом, может быть что-то похожее на mapValues
что было бы правильно, но не истинно map
на сборе.
TL; DR
map
действительно полезно, но будьте осторожны в том, что вы на самом деле делаете, потому что вы не можете действительно сделать map
С Set
для Set
.