Расширение 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 модуль (стандартная библиотека), потому что на самом деле не правильно для его реализации. Причина: mapping не просто перечисляет (что вы можете сделать с любым SequenceType на for-in), но он преобразует (с закрытием аргумента) каждое значение в другое. Таким образом, вы ожидаете, что результат будет иметь все transform(element) в нем, но думаю, что, если значения же они рушатся (ибо Dictionarys только ключи ведут себя таким образом).
например, (с предлагаемой реализации)
Set([1, 2, 3, 4, 5]).map { 1 }.count == 1
вот почему Swift.map возвращает Array и не тот же тип SequenceType/CollectionType прошло как , хотя с DictionaryС коллекции кортежей, а не только значение. Таким образом, может быть что-то похожее на mapValues что было бы правильно, но не истинно map на сборе.
TL; DR
map действительно полезно, но будьте осторожны в том, что вы на самом деле делаете, потому что вы не можете действительно сделать map С Set для Set.