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

x33g5p2x  于 2022-11-21  发布在  Swift
关注(0)|答案(4)|浏览(217)

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

wgx48brx

wgx48brx1#

一个很好的解决方法是在Swift Array上进行扩展,或者在这种情况下,为所有BidirectionalCollection对象(包括数组)提供一个更通用的解决方案。
下面提供了从数组中获取指定对象之后的下一个或上一个对象的方法,如果希望函数在数组末尾循环,则使用可选参数。
对于非循环函数,如果原始对象未出现在Array中,并且如果您要求第一个对象的前一项或最后一个对象之后的项,则这些函数返回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)

如果你只是想知道该轮到谁洗碗了,而昨晚是萨米洗碗,你可以用途:

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

这样,如果萨米是最小的孩子,那么当我们循环回到数组的开头时,他最大的兄弟姐妹今晚将被分配洗碗。

您可以使用集合的endIndex属性以外的任何有效索引,透过下标存取集合的元素。此属性是“超出结尾”的索引,不Map于集合的任何元素。

fhg3lkii

fhg3lkii2#

我建议一种更简单、更彻底的实现:

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.firstIndex(of: item)
            .flatMap(self.safeIndex(after:))
            .map{ self[$0] }
    }
    
    func item(afterWithWrapAround item: Element) -> Element? {
        return self.firstIndex(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.firstIndex(of: item)
            .flatMap(self.safeIndex(before:))
            .map{ self[$0] }
    }
    
    
    func item(beforeWithWrapAround item: Element) -> Element? {
        return self.firstIndex(of: item)
            .map(self.index(beforeWithWrapAround:))
            .map{ self[$0] }
    }
}
qyswt5oh

qyswt5oh3#

为什么不使用斯威夫特的工厂方法呢?
尝试使用此方法将上一个项目获取到对象。

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

首先获取您希望上一个项的对象的索引,然后获取该索引的项-1。

idv4meu8

idv4meu84#

import UIKit

扩展数组,其中元素:等同性{

/// Finds next element of the array, returns nil if there is no next element
func nextElement(element: Element, completion: @escaping(Element?)->()){
    let currentIndex = self.firstIndex { $0 == element}
    if let currIndex = currentIndex?.advanced(by: 1) {
        completion(currIndex >= self.endIndex ? nil : self[currIndex])
    }else{
        completion(nil)
    }
}

/// Finds prev element of the array, returns nil if there is no previous element
func prevElement(element: Element, completion: @escaping(Element?)->()){
    let currentIndex = self.firstIndex { $0 == element}
    if let currIndex = currentIndex?.advanced(by: -1) {
        completion(currIndex <= self.endIndex ? nil : self[currIndex])
    }else{
        completion(nil)
    }
}

}

相关问题