- Create normalized weighted ranges.
[ 0.0..<0.1,
0.1..<0.3,
0.3..<0.6,
0.6..<0.95,
0.95..<1.0
]
let normalizedWeightedRanges = [10, 20, 30, 35, 5].normalizedWeightedRanges
import Algorithms
public extension Sequence where Element: FloatingPoint {
/// Normalized (`0..<1`) representations of the elements' weights within their sum.
var normalizedWeightedRanges: [Range<Element>] {
guard let sum = sum else {
return []
}
return .init(
reductions(0..<0) {
$0.upperBound..<$1 / sum + $0.upperBound
}.dropFirst()
)
}
}
public extension Sequence where Element: AdditiveArithmetic {
var sum: Element? { reduce(+) }
}
public extension Sequence {
/// - Returns: `nil` If the sequence has no elements, instead of an "initial result".
func reduce(
_ nextPartialResult: (Element, Element) throws -> Element
) rethrows -> Element? {
var iterator = makeIterator()
return try iterator.next().map { first in
try IteratorSequence(iterator).reduce(first, nextPartialResult)
}
}
}
- Sample. (Binary search would be better than
firstIndex
.)
/// - precondition: `normalizedWeightedRanges` is the result of `Sequence.normalizedWeightedRanges`
func randomIndex<Float: BinaryFloatingPoint>(
inNormalizedWeightedRanges normalizedWeightedRanges: [Range<Float>]
) -> Int
where Float.RawSignificand: FixedWidthInteger {
normalizedWeightedRanges.firstIndex { [random = Float.random(in: 0..<1)] in
$0.contains(random)
}!
}