获取Swift集合或数组中对象的下一个或上一个项目

时间:2017-07-27 02:53:43

标签: arrays swift

在Swift数组中识别指定对象之前或之后的项目的最佳方法是什么,同时防止出界错误?

3 个答案:

答案 0 :(得分:8)

我提出了一个更简单,更彻底的实现:

extension Collection where Iterator.Element: Equatable {
    typealias Element = Self.Iterator.Element

    func safeIndex(after index: Index) -> Index? {
        let nextIndex = self.index(after: index)
        return (nextIndex < self.endIndex) ? nextIndex : nil
    }

    func index(afterWithWrapAround index: Index) -> Index {
        return self.safeIndex(after: index) ?? self.startIndex
    }

    func item(after item: Element) -> Element? {
        return self.index(of: item)
            .flatMap(self.safeIndex(after:))
            .map{ self[$0] }
    }

    func item(afterWithWrapAround item: Element) -> Element? {
        return self.index(of: item)
            .map(self.index(afterWithWrapAround:))
            .map{ self[$0] }
    }
}

extension BidirectionalCollection where Iterator.Element: Equatable {
    typealias Element = Self.Iterator.Element

    func safeIndex(before index: Index) -> Index? {
        let previousIndex = self.index(before: index)
        return (self.startIndex <= previousIndex) ? previousIndex : nil
    }

    func index(beforeWithWrapAround index: Index) -> Index {
        return self.safeIndex(before: index) ?? self.index(before: self.endIndex)
    }

    func item(before item: Element) -> Element? {
        return self.index(of: item)
            .flatMap(self.safeIndex(before:))
            .map{ self[$0] }
    }


    func item(beforeWithWrapAround item: Element) -> Element? {
        return self.index(of: item)
            .map(self.index(beforeWithWrapAround:))
            .map{ self[$0] }
    }
}

答案 1 :(得分:6)

解决这个问题的一个好方法是使用Swift数组的扩展,或者在这种情况下,为所有BidirectionalCollection对象(包括数组)提供更通用的解决方案。

以下提供了从数组中获取指定对象之后的下一个或上一个对象的方法,如果希望函数在数组的末尾循环,则使用可选参数。

如果原始对象在数组中不存在,并且如果要求前一项指向第一个对象或最后一个对象后面的项,则对于非循环函数,这些函数返回nil。

//
//  Array+Iterator.swift
//

extension BidirectionalCollection where Iterator.Element: Equatable {
    typealias Element = Self.Iterator.Element

    func after(_ item: Element, loop: Bool = false) -> Element? {
        if let itemIndex = self.index(of: item) {
            let lastItem: Bool = (index(after:itemIndex) == endIndex)
            if loop && lastItem {
                return self.first
            } else if lastItem {
                return nil
            } else {
                return self[index(after:itemIndex)]
            }
        }
        return nil
    }

    func before(_ item: Element, loop: Bool = false) -> Element? {
        if let itemIndex = self.index(of: item) {
            let firstItem: Bool = (itemIndex == startIndex)
            if loop && firstItem {
                return self.last
            } else if firstItem {
                return nil
            } else {
                return self[index(before:itemIndex)]
            }
        }
        return nil
    }
}

<强>用法: 如果您有一系列孩子,并想知道Jane之后的孩子,您将使用以下内容:

let nextChild = children.after(jane)

如果你只是想知道轮到你做什么菜,而Sammy昨晚做了这些菜,那你就改用:

let dishwasherTonight = children.after(sammy, loop: true)

这样一来,如果Sammy是最小的孩子,他们最老的兄弟姐妹将会被分配到今晚洗碗,因为我们会回到阵列的开头。

后记:请注意definition of that property代码中与endIndex的比较:

  

您可以通过下标来访问集合的元素   使用除集合的endIndex属性之外的任何有效索引。这个   property是一个“过去的结尾”索引,与任何不符   集合的元素。

答案 2 :(得分:0)

为什么不使用 Swift 的工厂方法?

试试这个来获取对象的前一项。

                let currentIndex = yourArr.index(of: "0")
                let previousVal = yourArr[currentIndex-1]

首先获取您想要上一项的对象的索引, 然后得到那个 index-1 的项目。