I was using the protocols for code re-use not for generic algorithms, but in this case the code is short - so here is a version that repeats the code in Set
and Dictionary
:
import Foundation
extension RangeReplaceableCollection {
init(_ count: Int, _ generator: () throws -> Element) rethrows {
self.init()
reserveCapacity(count)
for _ in 0 ..< count {
append(try generator())
}
}
}
Array(5) {
0
} // [0, 0, 0, 0, 0]
ArraySlice(5) {
1
} // [1, 1, 1, 1, 1]
ContiguousArray(5) {
2
} // [2, 2, 2, 2, 2]
Data(5) {
3
} // [3, 3, 3, 3, 3]
String(5) {
"A"
} // "AAAAA"
String.UnicodeScalarView(5) {
"B"
} // "BBBBB"
Substring(5) {
"C"
} // "CCCCC"
Substring.UnicodeScalarView(5) {
"D"
} // {... "DDDDD"}
extension Set {
init(_ count: Int, _ generator: () throws -> Element) rethrows {
self.init()
reserveCapacity(count)
for _ in 0 ..< count {
update(with: try generator())
}
}
}
Set(5) {
Int.random(in: 0 ... 9)
} // {2, 1, 6} - up to 5 random decimal digits
extension RangeReplaceableCollection where Index == Int {
init(_ count: Int, _ generator: (Int) throws -> Element) rethrows {
self.init()
reserveCapacity(count)
for index in 0 ..< count {
insert(try generator(index), at: index)
}
}
}
Array(5) { index in
index
} // [0, 1, 2, 3, 4]
ArraySlice(5) { index in
index + 1
} // [1, 2, 3, 4, 5]
ContiguousArray(5) { index in
index + 2
} // [2, 3, 4, 5, 6]
extension Dictionary where Key == Int {
init(_ count: Int, _ generator: (Int) throws -> Value) rethrows {
self.init()
reserveCapacity(count)
for index in 0 ..< count {
self[index] = try generator(index)
}
}
}
Dictionary(5) { index in
index
} // [3: 3, 1: 1, 2: 2, 0: 0, 4: 4] - in some order.
It still retains the desirable characteristics of:
- Short to use.
- Highly discoverable in Xcode.
- You can't get confused because the index isn't an Int (it must be an Int).
- Can be applied to other collection types as well as
Array
.