I made a protocol
protocol IndexConvertable{
associatedtype T
static func convertAnyTypeToInt(_ type: Self) -> Int
static func convertIntToAnyType(_ int: Int) -> Self
}
The protocol allows me to index a type that has unlimited bidirectional values, eg. Date
eg.
extension Date: IndexConvertable{
typealias T = Date
static func convertAnyTypeToInt(_ date: Date) -> Int {
date.convertDateToInt()
}
static func convertIntToAnyType(_ int: Int) -> Date {
int.convertIntToDate()
}
}
extension Date{
/// This function converts a Date to an Int.
func convertDateToInt(){
...
}
}
extension Int{
/// This function converts an Int to a Date.
func convertIntToDate{
...
}
}
Logically, any array where the type of the array element are the same, can be convert to bidirectional endless sequence by looping the given values.
Example 1:
let colors: [Color] = [.red, .blue, .purple]
goal => [... .red, .blue, .purple, .red, .blue, .purple ...]
Example 2:
struct ColorView: View{
let color: Color
var body: some View{
color.ignoreSafeArea()
}
}
let colorViews: [ColorView] = [
ColorView(color: .red),
ColorView(color: .blue),
ColorView(color: .purple)
]
=> [... ColorView(color: .red), ColorView(color: .blue), ColorView(color: .purple), ColorView(color: .red), ColorView(color: .blue), ColorView(color: .purple) ...]
Conversion calculations:
let c: [Color] = [.red, .blue, .purple]
x | -5 | -4 | -3 | -2 | -1 | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|---|---|---|---|---|
c[y] | c[1] | c[2] | c[0] | c[1] | c[2] | c[0] | c[1] | c[2] | c[0] | c[1] | c[2] |
.blue | .purple | .red | .blue | .purple | .red | .blue | .purple | .red | .blue | .purple |
let count = c.count
//Formula
y = { //if x is positive
if x >= 0{
x % count
}else{ //if x is negative
((x % count) count) % count
}
}()
The formula applies to array even when the length is different.
Any array where the type of the array element are the same, can be convert to bidirectional endless sequence by looping the given values.
I don't want to write extensions for each and every type that can be included in the array.
How can I fulfil the requirements? Or any method achieve the same goal are welcome.
CodePudding user response:
You have two unrelated questions. This is the answer for the second one:
Algorithms offers cycled
. If that doesn't suit your needs,
public extension Collection {
/// Circularly wraps `index`, to always provide an element,
/// even when `index` is not valid.
subscript(modulo index: Index) -> Element {
self[
self.index(
startIndex,
offsetBy:
distance(from: startIndex, to: index)
.modulo(count)
)
]
}
public extension BinaryInteger {
func modulo(_ divisor: Self) -> Self {
(self % divisor divisor) % divisor
}
}
Array(0...1)[modulo: -1] // 1
Array(0...1)[modulo: 2] // 0
CodePudding user response:
You can constrain an extension based on a generic type, so you could do something like this
extension Collection where Index == Int {
public subscript(index: Int, circular isCircular: Bool) -> Element {
if !isCircular {
return self[index]
}
let remainder = index % count
let validIndex = remainder < Index.zero ? count remainder : remainder
return self[validIndex]
}
}
Example of using it
let numbers = [1, 2, 3, 4, 5]
numbers[-1, circular: true] // 5
numbers[6, circular: true] // 2
numbers[6] // out of bounds
let letters = ["a", "b", "c"]
letters[3, circular: true] // "a"