Вот как я бы это сделал:
// Prints sequences of bools using 1/0s for easy reading
func p<S: Sequence>(_ bools: S) where S.Element == Bool {
print(bools.map { $0 ? "1" : "0"}.joined())
}
// E.g. makeWindow(span: 3) returns 0001
func makeWindow(span: Int) -> UnfoldSequence<Bool, Int> {
return sequence(state: span) { state in
state -= 1
switch state {
case -1: return nil
case 0: return true
case _: return false
}
}
}
// E.g. calculateSpacePositions(spans: [4, 6, 5]) returns 000100000100001
func calculateSpacePositions<S: Sequence>(spans: S)
-> LazySequence<FlattenSequence<LazyMapSequence<S, UnfoldSequence<Bool, Int>>>>
where S.Element == Int {
return spans.lazy.flatMap(makeWindow(span:))
}
extension String {
func insertingSpaces(at spans: [Int]) -> String {
let spacePositions = calculateSpacePositions(spans: spans + [Int.max])
// p(spacePositions.prefix(self.count))
let characters = zip(inputString, spacePositions)
.flatMap { character, shouldHaveSpace -> [Character] in
return shouldHaveSpace ? [character, "_"] : [character]
}
return String(characters)
}
}
let inputString = "1234123412341234"
let result = inputString.insertingSpaces(at: [4, 6, 5])
print(result)
Основная идея заключается в том, что я хочу zip(self, spacePositions)
, чтобы я получил последовательность символов self
вместе с логическим значением, которое говорит мне, если я должен добавить пробел после текущего символа.
Чтобы вычислить spacePositions
, я сначала начал с создания функции, которая при вводе Int
input span
вернула бы span
false
с, за которыми следует true
. Например, makeWindow(span: 3)
возвращает последовательность, которая дает false, false, false, true
.
. Оттуда просто нужно сделать один из этих windows для каждого элемента ввода и объединить их все вместе, используя flatMap
. Я делаю это все лениво, так что нам на самом деле не нужно хранить все эти повторяющиеся логические значения.
Я попал в одну загадку. Если вы дадите ввод [4, 6, 5]
, я бы использовал вывод 4
символов, пробел, 6
символов, пробел, 5
символов, конец. Остальная часть строки была потеряна, потому что zip
дает последовательность, длина которой равна длине более короткого из двух входов.
Чтобы исправить это, я добавляю Int.max
к spans
вход. Таким образом, позиции в пространстве будут 000010000001000001 ...now followed by Int.max falses
.