You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现同类型元素数组的双向无限循环序列(免逐个类型扩展)

实现任意数组的双向无限序列

我定义了如下协议:

protocol IndexConvertable{
    associatedtype T
    static func convertAnyTypeToInt(_ type: Self) -> Int
    static func convertIntToAnyType(_ int: Int) -> Self
}

该协议用于实现拥有双向无限取值的类型(比如Date)与Int的互转,示例如下:

extension Date: IndexConvertable{
    typealias T = Date
    
    static func convertAnyTypeToInt(_ date: Date) -> Int {
         date.convertDateToInt()
    }
    
    static func convertIntToAnyType(_ int: Int) -> Date {
         int.convertIntToDate()
    }
}

extension Date{
    /// 将Date转换为Int
    func convertDateToInt(){
        ...
    }
}

extension Int{
    /// 将Int转换为Date
    func convertIntToDate(){
        ...
    }
}

从逻辑上来说,任意元素类型相同的数组都可以通过循环映射转换为双向无限序列,比如:

示例1

let colors: [Color] = [.red, .blue, .purple]

目标序列 => [... .red, .blue, .purple, .red, .blue, .purple ...]

示例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) ...]

转换的计算方式如下(以[Color]为例):

x-5-4-3-2-1012345
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

// 计算目标索引y的公式
let y = {
    if x >= 0 {
        x % count
    } else {
        ((x % count) + count) % count
    }
}()

这个公式适用于任意长度的数组。现在需要实现将任意同类型元素的数组转换为双向无限序列,但不想为每个数组元素类型编写扩展,请问该如何实现?或者有其他能达成相同目标的方法也可以。


解决方案

方法1:自定义随机访问集合实现双向无限序列

创建一个通用包装类型,遵循RandomAccessCollection协议,内部持有原数组,通过重写索引计算逻辑实现双向无限循环,支持正负索引直接访问:

struct InfiniteCycledCollection<Element>: RandomAccessCollection {
    typealias Index = Int
    private let base: [Element]
    
    init(base: [Element]) {
        precondition(!base.isEmpty, "原数组不能为空")
        self.base = base
    }
    
    // 无限序列无实际起止索引,用Int极值占位以符合协议要求
    var startIndex: Index { Int.min }
    var endIndex: Index { Int.max }
    
    subscript(position: Index) -> Element {
        let count = base.count
        let adjustedIndex = position >= 0 
            ? position % count 
            : ((position % count) + count) % count
        return base[adjustedIndex]
    }
    
    func index(after i: Index) -> Index { i + 1 }
    func index(before i: Index) -> Index { i - 1 }
}

// 给Array添加便捷转换方法
extension Array {
    func infiniteCycled() -> InfiniteCycledCollection<Element> {
        InfiniteCycledCollection(base: self)
    }
}

使用示例:

let colors = [Color.red, .blue, .purple].infiniteCycled()
print(colors[-5]) // 输出 .blue
print(colors[0])  // 输出 .red
print(colors[5])  // 输出 .purple

方法2:自定义序列生成器(支持双向迭代)

如果不需要随机访问特性,可创建双向迭代的无限序列生成器:

struct InfiniteCycleSequence<Element>: Sequence, IteratorProtocol {
    private let base: [Element]
    private var currentIndex: Int = 0
    
    init(base: [Element]) {
        precondition(!base.isEmpty, "原数组不能为空")
        self.base = base
    }
    
    mutating func next() -> Element? {
        let element = base[currentIndex]
        currentIndex = (currentIndex + 1) % base.count
        return element
    }
    
    // 扩展反向迭代能力
    func reversed() -> ReversedInfiniteCycleSequence<Element> {
        ReversedInfiniteCycleSequence(base: base)
    }
}

struct ReversedInfiniteCycleSequence<Element>: Sequence, IteratorProtocol {
    private let base: [Element]
    private var currentIndex: Int
    
    init(base: [Element]) {
        precondition(!base.isEmpty, "原数组不能为空")
        self.base = base
        self.currentIndex = base.count - 1
    }
    
    mutating func next() -> Element? {
        let element = base[currentIndex]
        currentIndex = currentIndex > 0 ? currentIndex - 1 : base.count - 1
        return element
    }
}

// 给Array添加便捷转换方法
extension Array {
    func infiniteCycle() -> InfiniteCycleSequence<Element> {
        InfiniteCycleSequence(base: self)
    }
}

使用示例:

let colorViews = [
    ColorView(color: .red),
    ColorView(color: .blue),
    ColorView(color: .purple)
].infiniteCycle()

// 正向遍历前5个元素
var forwardIterator = colorViews.makeIterator()
for _ in 0..<5 {
    print(forwardIterator.next())
}

// 反向遍历前3个元素
var reversedIterator = colorViews.reversed().makeIterator()
for _ in 0..<3 {
    print(reversedIterator.next())
}

方法3:利用标准库cycled()(仅正向无限)

如果只需要正向无限序列,可导入Swift的Algorithms包,直接使用标准库提供的cycled()方法,无需自定义类型:

import Algorithms

let colors = [Color.red, .blue, .purple].cycled()

注意:该方法生成的序列不支持负索引访问,仅适用于正向无限遍历场景。


内容的提问来源于stack exchange,提问作者Harry CHOI

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 13:00:50