简体   繁体   中英

An array where all the element are the same type, make the element conforms to some protocol

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.

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
  }
}
[0, 1][modulo: -1] // 1
[0, 1][modulo: 2] // 0

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"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM