seq.stateMap(_:_:)
Last updated
Last updated
extension Sequence {
/// `seq.stateMap(_:_:)`:
/// map a sequence with a local state.
public func stateMap<State, Result>(
// intial local state
_ initialState: State,
// calculate the result from current element & state,
// state may be updated upon each call.
_ result: (inout State, Element) -> Result
) -> [Result] {
var state = initialState
return map { elem in
return result(&state, elem)
}
}
}
// example dictionary
let dict = [
"Sam": 79, "Joe": 5, "Mary": 79,
"Tom": 5, "Alex": 82, "Nancy": 1
]
typealias State = (prev: Int?, currentRank: Int, index: Int)
typealias Result = (name: String, score: Int, rank: Int)
let intialState: State = (prev: nil, currentRank: 0, index: 0)
let list = dict
.sorted { $0.value > $1.value }
// โญ๏ธ calculate next result from state & current element,
// update local state (if necessary) and return next result.
.stateMap(intialState) { (state: inout State, elem) -> Result in
// increase index
state.index += 1
// if elem.value is not the same as previous score,
// update previous score and current rank
if state.prev == nil || elem.value != state.prev! {
state.prev = elem.value
state.currentRank = state.index
}
return (elem.key, elem.value, state.currentRank)
}
print(list)
/*
[
(name: "Alex" , score: 82, rank: 1),
(name: "Sam" , score: 79, rank: 2),
(name: "Mary" , score: 79, rank: 2), // no 3rd place
(name: "Joe" , score: 5, rank: 4),
(name: "Tom" , score: 5, rank: 4), // no 5th place
(name: "Nancy", score: 1, rank: 6)
]
*/
Advanced Swift (2019.05), p. 34