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

Dun*_*age 10 arrays swift

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

Dun*_*age 11

解决这个问题的一个好方法是使用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
    }
}
Run Code Online (Sandbox Code Playgroud)

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

let nextChild = children.after(jane)
Run Code Online (Sandbox Code Playgroud)

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

let dishwasherTonight = children.after(sammy, loop: true)
Run Code Online (Sandbox Code Playgroud)

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


后记:注意在代码中将endIndex 与该属性定义进行比较:

您可以使用除集合的endIndex属性之外的任何有效索引通过其下标访问集合的元素.此属性是"过去结束"索引,与集合的任何元素都不对应.

  • 我认为你在问问题之前已经准备好了答案。哈哈..有用的答案:) (2认同)

Ale*_*ica 10

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

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] }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 更具可读性...“获取事物的索引,如果存在,获取其后的索引,如果存在,获取该索引处的元素” (2认同)