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

The elegant solution for function that gives everytime called different element of array(ordered and starting from new when all returned)?

我是新手,想知道我的代码的 elegant/Grown-up 解决方案是什么。

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

“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"] 数组的背景颜色。因此,当多次单击它时,背景会变红、变绿、变蓝、变红……不是随机的,也不是结束的。

我觉得你在谈论循环函数。它将有限序列连接成循环序列,无限重复原始序列。您需要惰性求值才能完成此操作。

public struct LazyCycleIterator <Base: Sequence>: IteratorProtocol {
  public typealias Element = Base.Element

  private var baseSequence: Base
  private var baseIterator: Base.Iterator

  internal init (_ baseSequence: Base) {
    self.baseSequence = baseSequence
    self.baseIterator = baseSequence.makeIterator()
  }

  public mutating func next () -> Element? {
    var next = self.baseIterator.next()

    if next == nil {
      self.baseIterator = self.baseSequence.makeIterator()
      next = self.baseIterator.next()
    }

    return next
  }
}

public struct LazyCycleSequence <Base: Sequence>: LazySequenceProtocol {
  public typealias Iterator = LazyCycleIterator<Base>

  private let iterator: Iterator

  internal init (_ baseSequence: Base) {
    self.iterator = Iterator(baseSequence)
  }

  public func makeIterator () -> Iterator {
    return self.iterator
  }
}

public extension Sequence {
  var cycle: LazyCycleSequence<Self> {
    return LazyCycleSequence(self)
  }
}

然后您可以在任何 Sequence:

上这样调用它
print(Array([1, 2, 3].cycle.prefix(10)))

或者,如果您只想继续获取下一个值,请执行以下操作:

var iterator = [1, 2, 3].cycle.makeIterator()

print(iterator.next()!) // 1
print(iterator.next()!) // 2
print(iterator.next()!) // 3
print(iterator.next()!) // 1
// Etc.

更新: Swift Algorithms package incorporates exactly this algorithm, under the name Cycle<T>. See https://github.com/apple/swift-algorithms/blob/main/Guides/Cycle.md

这个“弹出”过程实际上是自定义序列的迭代...。 在 Swift 中表示它的适当方式是作为实现 IteratorProtocol 的类型 (struct/class)。我叫我的 CycleIterator 。很少直接使用迭代器。相反,它们通常由符合 Sequence 的类型提供。我叫我的 CycleSequence

Sequence 协议仅要求符合类型提供一个函数,makeIterator(),return 是一个迭代器(CycleIterator 在我的例子中)。只需这样做,您就可以立即获得序列的所有功能。可迭代性,map/filter/reduceprefixsuffix

IteratorProtocol 只需要此类型提供一个函数 next(),它产生 return 一个 Element?。 return 值是可选的,因为 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! \([=11=])" }.forEach{ print([=11=]) }


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)))

定义:

struct CircularQueue<T> {

    private var array       : [T]
    private var iterator    : IndexingIterator<[T]>

    init(array: [T]) {
        self.array = array
        iterator = array.makeIterator()
    }

    mutating func pop() -> T? {

        guard !array.isEmpty else {
            return nil
        }

        let nextElement : T

        if let element = iterator.next() {

            nextElement = element
        }
        else {
            iterator = array.makeIterator()
            return pop() //Recursive
        }

        return nextElement
    }
}

正在调用:

var queue1 = CircularQueue(array: Array(1...3))

print(queue1.pop())
print(queue1.pop())
print(queue1.pop())
print(queue1.pop())
print(queue1.pop())

var queue2 = CircularQueue(array: ["a", "b"])

print(queue2.pop())
print(queue2.pop())
print(queue2.pop())
print(queue2.pop())
print(queue2.pop())

A​​lexander 的回答很棒,但可以简化。

public struct CircularSequence<Iterator: IteratorProtocol>: Sequence {
  public init<Sequence: Swift.Sequence>(_ sequence: Sequence)
  where Sequence.Iterator == Iterator {
    makeIterator = sequence.makeIterator
    iterator = makeIterator()
  }

  private var iterator: Iterator
  private let makeIterator: () -> Iterator
}

//MARK: IteratorProtocol
extension CircularSequence: IteratorProtocol {
  public mutating func next() -> Iterator.Element? {
    if let next = iterator.next() {
      return next
    }
    else {
      iterator = makeIterator()
      return iterator.next()
    }
  }
}

如果需要,您可以随时获取迭代器:

enum : CaseIterable { case , ,  }

let circularSequence = CircularSequence(.allCases)
let anySequence = AnySequence(cycling: .allCases)

func makePrefixArray<Sequence: Swift.Sequence>(_ sequence: Sequence) -> [Sequence.Element] {
  .init( sequence.prefix(5) )
}
let fiveBats = [., ., ., ., .]
XCTAssertEqual(makePrefixArray(circularSequence), fiveBats)
XCTAssertEqual(makePrefixArray(anySequence), fiveBats)

var circularSequenceIterator = circularSequence.makeIterator()
let anySequenceIterator = anySequence.makeIterator()
for _ in 1...(.allCases.count * 2 + 1) {
  _ = ( circularSequenceIterator.next(), anySequenceIterator.next() )
}
XCTAssertEqual(circularSequenceIterator.next(), .)
XCTAssertEqual(anySequenceIterator.next(), .)
public extension AnySequence {
  init<Sequence: Swift.Sequence>(cycling sequence: Sequence)
  where Sequence.Element == Element {
    self.init { [makeIterator = sequence.makeIterator] in
      Iterator( state: makeIterator() ) { iterator in
        if let next = iterator.next() {
          return next
        }
        else {
          iterator = makeIterator()
          return iterator.next()
        }
      }
    }
  }
}
public extension AnyIterator {
  /// Use when `AnyIterator` is required / `UnfoldSequence` can't be used.
  init<State>(
    state: State,
    _ getNext: @escaping (inout State) -> Element?
  ) {
    var state = state
    self.init { getNext(&state) }
  }
}