如何循环遍历数组以找到4个连续的相同值?

时间:2015-10-28 19:33:21

标签: arrays swift

我有以下swift数组:

var winSuitArray = [cardSuit1, cardSuit2, cardSuit3, cardSuit4, cardSuit5, cardSuit6, cardSuit7]

cardSuit1cardSuit2等等,是与" club"等字符串相等的变量。或"心脏"。我想要做的是循环遍历此数组,如果循环找到4个索引连续的相同对象,请将winSuitStatus bool设置为true

例如,如果数组如下所示:

["hearts", "clubs", "clubs", "clubs", "clubs", "diamonds", "spades"]

我想像这样循环:

for card in winSuitArray {
    //find 4 identical and consecutive objects
    // if the above requirements are met, let winSuitStatus = true
}

这可能吗?

3 个答案:

答案 0 :(得分:4)

说实话,我可能会做类似于@ KnightOfDragon的回答。这种方法没有错。但是这个问题为以更低的成本构建更多可重用的代码提供了一些机会,所以这样做似乎有点麻烦。

基本问题是你想在列表上创建一个给定大小的滑动窗口,然后你想知道是否有任何窗口只包含一个值。所以创建这些窗口的第一个问题。我们可以非常普遍地为所有集合做到这一点,我们可以懒得做,所以我们不必计算所有窗口(我们可能会在列表的开头找到答案)。

extension Collection {
    func slidingWindow(length: IndexDistance) -> AnyRandomAccessCollection<SubSequence> {
        guard length <= count else { return AnyRandomAccessCollection([]) }

        let windows = sequence(first: (startIndex, index(startIndex, offsetBy: length)),
                               next: { (start, end) in
                                let nextStart = self.index(after: start)
                                let nextEnd = self.index(after: end)
                                guard nextEnd != self.endIndex else { return nil }
                                return (nextStart, nextEnd)
        })

        return AnyRandomAccessCollection(
            windows.lazy.map{ (start, end) in self[start..<end] }
        )
    }
}

这里使用AnyRandomAccessCollection只是隐藏延迟的实现细节。否则我们必须返回LazyMapSequence<UnfoldSequence<(Index, Index), ((Index, Index)?, Bool)>, SubSequence>,这会有点疯狂。

现在接下来的问题是窗口中的所有元素是否相等。我们可以为任何类似的Equatable序列做到这一点:

extension Sequence where Iterator.Element: Equatable {
    func allEqual() -> Bool {
        var g = makeIterator()
        guard let f = g.next() else { return true }
        return !contains { $0 != f }
    }
}

有了这两件,我们可以问我们的问题。在长度为4的窗口中,是否存在任何相同的区域?

let didWin = suits.slidingWindow(length: 4).contains{ $0.allEqual() }

或者我们可以采用一种不同的方式,并创建一个我们可以迭代的SlidingWindowSequence。这里的逻辑基本相同。这只是将窗口包装成特定类型而不是AnyRandomAccessCollection。对于这个问题,这可能有点过头了,但它展示了另一个强大的模式。

public struct SlidingWindowSequence<Base: Collection>: Sequence, IteratorProtocol {
    let base: Base
    let windowSize: Base.IndexDistance

    private var windowStart: Base.Index

    public init(_ base: Base, windowSize: Base.IndexDistance) {
        self.base = base
        self.windowSize = windowSize
        self.windowStart = base.startIndex
    }

    public mutating func next() -> Base.SubSequence? {
        if base.distance(from: windowStart, to: base.endIndex) < windowSize {
            return nil
        }

        let window = base[windowStart..<base.index(windowStart, offsetBy: windowSize)]
        windowStart = base.index(after: windowStart)
        return window
    }
}

let didWin = SlidingWindowSequence(suits, windowSize: 4).contains{ $0.allEqual() }

答案 1 :(得分:2)

var suit = ""
var count = 1
for card in winSuitArray {
    if(suit == card)
    {
        count++
    }
    else
    {
      count = 1
      suit = card
    }        

    if(count == 4)
    { 
        //find 4 identical and consecutive objects
        // if the above requirements are met, let winSuitStatus = true
    }
}

答案 2 :(得分:0)

您可以使用计数器变量来执行此操作,初始化为1。

for each value in array:
    if value equals previous value
        increment counter
    else
        counter = 1
    if counter >= 4
        set winCounter to true