У меня есть список животных:
let animals = ["bear", "dog", "cat"]
И некоторые способы преобразовать этот список:
typealias Transform = (String) -> [String]
let containsA: Transform = { $0.contains("a") ? [$0] : [] }
let plural: Transform = { [$0 + "s"] }
let double: Transform = { [$0, $0] }
В некотором смысле, они аналогичны фильтру (выходы 0 или1 элемент), map (ровно 1 элемент) и flatmap (более 1 элемента) соответственно, но определены единообразно, чтобы их можно было обрабатывать согласованно.
Я хочу создать ленивый итератор, который применяет массивиз них преобразуется в список животных:
extension Array where Element == String {
func transform(_ transforms: [Transform]) -> AnySequence<String> {
return AnySequence<String> { () -> AnyIterator<String> in
var iterator = self
.lazy
.flatMap(transforms[0])
.flatMap(transforms[1])
.flatMap(transforms[2])
.makeIterator()
return AnyIterator {
return iterator.next()
}
}
}
}
, что означает, что я могу лениво сделать:
let transformed = animals.transform([containsA, plural, double])
и проверить результат:
print(Array(transformed))
IЯ доволен, насколько это кратко, но ясно:
.flatMap(transforms[0])
.flatMap(transforms[1])
.flatMap(transforms[2])
- это проблема, поскольку она означает, что функция преобразования будет работать только с массивом из 3 преобразований.
Редактировать: Я пытался:
var lazyCollection = self.lazy
for transform in transforms {
lazyCollection = lazyCollection.flatMap(transform) //Error
}
var iterator = lazyCollection.makeIterator()
, но в отмеченной строке я получаю ошибку:
Невозможно присвоить значение типа 'LazyCollection ,[String] >>> «набрать» LazyCollection > '
, которыйЯ понимаю, потому что каждый раз вокруг цикла добавляется еще одна плоская карта, поэтому тип меняется.
Как заставить функцию преобразования работать с массивом любого числа преобразований?
Одно решение WET для ограниченного числа преобразований будет (но YUK!)
switch transforms.count {
case 1:
var iterator = self
.lazy
.flatMap(transforms[0])
.makeIterator()
return AnyIterator {
return iterator.next()
}
case 2:
var iterator = self
.lazy
.flatMap(transforms[0])
.flatMap(transforms[1])
.makeIterator()
return AnyIterator {
return iterator.next()
}
case 3:
var iterator = self
.lazy
.flatMap(transforms[0])
.flatMap(transforms[1])
.flatMap(transforms[2])
.makeIterator()
return AnyIterator {
return iterator.next()
}
default:
fatalError(" Too many transforms!")
}
Весь код:
let animals = ["bear", "dog", "cat"]
typealias Transform = (String) -> [String]
let containsA: Transform = { $0.contains("a") ? [$0] : [] }
let plural: Transform = { [$0 + "s"] }
let double: Transform = { [$0, $0] }
extension Array where Element == String {
func transform(_ transforms: [Transform]) -> AnySequence<String> {
return AnySequence<String> { () -> AnyIterator<String> in
var iterator = self
.lazy
.flatMap(transforms[0])
.flatMap(transforms[1])
.flatMap(transforms[2])
.makeIterator()
return AnyIterator {
return iterator.next()
}
}
}
}
let transformed = animals.transform([containsA, plural, double])
print(Array(transformed))