小编典典

提供给函数的优雅解决方案每次都调用数组的不同元素(有序并在所有返回时从新开始)?

swift

我是新手,不知道我的代码会是什么样的优雅/成长型解决方案。

我也很感谢我能找到与此相关的术语,这似乎是一项常见的任务。

“ 1,2,3” 只是占位符,因此解决方案不应依赖于它们是数字

var myValues = [1,2,3]
//function, that returns one element from array, in order, and starts 
//from beginning when all elements been returned once,twice etc.
func popper() -> Int {
     let returnValue = myValues.popLast()
     myValues.insert(returnValue!, at: 0)
     return returnValue!

popper() = 3
popper() = 2
popper() = 1
popper() = 3
...

以最后一个1231231开始并不重要…也很棒!

编辑:也许更具描述性的示例:

我有一个单击按钮,可从[“ red”,“ green”,“
blue”]数组更改背景色。因此,当多次单击它时,背景变成红色,变成绿色,变成蓝色,变成红色…不是随机的,并且没有结束。


阅读 247

收藏
2020-07-07

共1个答案

小编典典

“弹出”的过程实际上是自定义序列的迭代。在Swift中表示这种情况的适当方式是作为实现的类型(struct/
classIteratorProtocol。我打电话给我CycleIterator。迭代器很少直接使用。而是通常由符合的类型提供Sequence。我打电话给我CycleSequence

Sequence协议只需要使用符合条件的类型来提供一个函数makeIterator(),该函数会返回一个迭代器(CycleIterator在我的情况下)。只需执行此操作,即可立即获得序列的所有功能。Iterability,map/
filter/ reduceprefixsuffix等。

IteratorProtocol只要求这种类型提供一个函数,next(),这产生一个返回Element?。返回值是可选的,nil用于表示序列的结尾。

这是我将如何实现这些方法:

public struct CycleSequence<C: Collection>: Sequence {
    public let cycledElements: C

    public init(cycling cycledElements: C) {
        self.cycledElements = cycledElements
    }

    public func makeIterator() -> CycleIterator<C> {
        return CycleIterator(cycling: cycledElements)
    }
}

public struct CycleIterator<C: Collection>: IteratorProtocol {
    public let cycledElements: C
    public private(set) var cycledElementIterator: C.Iterator

    public init(cycling cycledElements: C) {
        self.cycledElements = cycledElements
        self.cycledElementIterator = cycledElements.makeIterator()
    }

    public mutating func next() -> C.Iterator.Element? {
        if let next = cycledElementIterator.next() {
            return next
        } else {
            self.cycledElementIterator = cycledElements.makeIterator() // Cycle back again
            return cycledElementIterator.next()
        }
    }
}



let s1 = CycleSequence(cycling: [1, 2, 3]) // Works with arrays of numbers, as you would expect.
// Taking one element at a time, manually
var i1 = s1.makeIterator()
print(i1.next() as Any) // => Optional(1)
print(i1.next() as Any) // => Optional(2)
print(i1.next() as Any) // => Optional(3)
print(i1.next() as Any) // => Optional(1)
print(i1.next() as Any) // => Optional(2)
print(i1.next() as Any) // => Optional(3)
print(i1.next() as Any) // => Optional(1)

let s2 = CycleSequence(cycling: 2...5) // Works with any Collection. Ranges work!
// Taking the first 10 elements
print(Array(s2.prefix(10))) // => [2, 3, 4, 5, 2, 3, 4, 5, 2, 3]

let s3 = CycleSequence(cycling: "abc") // Strings are Collections, so those work, too!
s3.prefix(10).map{ "you can even map over me! \($0)" }.forEach{ print($0) }


print(Array(CycleSequence(cycling: [true, false]).prefix(7))) // => [true, false, true, false, true, false, true]
print(Array(CycleSequence(cycling: 1...3).prefix(7))) // => [1, 2, 3, 1, 2, 3, 1]
print(Array(CycleSequence(cycling: "ABC").prefix(7))) // => ["A", "B", "C", "A", "B", "C", "A"]
print(Array(CycleSequence(cycling: EmptyCollection<Int>()).prefix(7))) // => []
print(Array(zip(1...10, CycleSequence(cycling: "ABC")))) // => [(1, "A"), (2, "B"), (3, "C"), (4, "A"), (5, "B"), (6, "C"), (7, "A"), (8, "B"), (9, "C"), (10, "A")]

这是一个简短的替代实现,展示了如何sequence(state:next:)用于实现相似的目标。

func makeCycleSequence<C: Collection>(for c: C) -> AnySequence<C.Iterator.Element> {
    return AnySequence(
        sequence(state: (elements: c, elementIterator: c.makeIterator()), next: { state in
            if let nextElement = state.elementIterator.next() {
                return nextElement
            }
            else {
                state.elementIterator = state.elements.makeIterator()
                return state.elementIterator.next()
            }
        })
    )
}

let repeater = makeCycleSequence(for: [1, 2, 3])
print(Array(repeater.prefix(10)))
2020-07-07