【问题标题】:Best way to locate data in nested arrays in swift快速定位嵌套数组中数据的最佳方法
【发布时间】:2021-03-14 19:47:55
【问题描述】:

给定嵌套对象的数据如下:

struct Store{
    var name: String
    var items: [Item]
}
 

struct Item{
    var name: String
    var free: Bool
}
 

var dataSet = [
    Store(name: "firstStore", items: [
        Item(name: "item1", free: false), Item(name: "item2", free: false),   Item(name: "item3", free: true),
    ]),
    
    Store(name: "secStore", items: [
        Item(name: "item4", free: true), Item(name: "item5", free: false),   Item(name: "item6", free: true),
    ]),
    
    Store(name: "thiStore", items: [
        Item(name: "item7", free: false), Item(name: "item8", free: true),   Item(name: "item9", free: false),
    ]),
    
    Store(name: "lastStore", items: [
        Item(name: "item10", free: true), Item(name: "item11", free: false),   Item(name: "item12", free: true),
    ]),
]

通过给定一个部分(商店)和一行(项目)作为起点,我需要找到满足某些条件的下一个/上一个项目(在这种情况下是免费的)。我将使用 IndexPath 来标注位置。这些方法不仅应该返回项目,还应该返回位置(由 IndexPath 表示)。

这就是我得到的。它正在工作,但肯定有更好更干净的存档方式。

func nextFree(from start: IndexPath) -> (Item, IndexPath)?{
    for (section, store) in dataSet.enumerated().dropFirst(start.section) {
        for (row, item) in store.items.enumerated().filter({$0.element.free}){
            if section == start.section && row <= start.row { continue }
            return (item, IndexPath(row: row, section: section))
        }
    }
    return nil
}
 

func previousFree(from start: IndexPath) -> (Item, IndexPath)?{
    for (section, store) in dataSet.enumerated().reversed(){
        if section > start.section { continue }
        for (row, item) in store.items.enumerated().reversed().filter({$0.element.free}){
            if section == start.section && row >= start.row { continue }
            return (item, IndexPath(row: row, section: section))
        }
    }
    return nil
}

最干净、最高效的方法是什么?

【问题讨论】:

    标签: swift algorithm multidimensional-array collections


    【解决方案1】:

    在 Swift 中,我们经常想使用所有花哨的功能,虽然有时利用 mapfilterreducezip 等超级有用的功能可能是个好主意简单的解决方案最适合给定的用例。

    这显然是非常固执的答案,但这个问题要求这种性质的答案,所以这是我的。

    我相信您通过简单的for-loop 实现走在正确的道路上。这提高了可读性,并允许您在找到要查找的结果后快速返回。这是稍微改进的版本,带有where 子句。

    func nextFree(from start: IndexPath) -> (Item, IndexPath)? {
        let sections = dataSet.enumerated().dropFirst(start.section)
        for (section, store) in sections {
            let rows = store.items.enumerated().filter { $0.element.free }
            for (row, item) in rows where section != start.section || row > start.row {
                return (item, IndexPath(row: row, section: section))
            }
        }
        return nil
    }
    

    前面提到的其他函数,如 mapfilterreduce 不会给我们所需的灵活性,在这种情况下,简单的 for-loop 非常有用且易于理解。除了添加 where 子句之外,唯一要做的事情是为您正在迭代的枚举集合使用单独的属性,因为它会在读取代码的每个生命周期时降低复杂性。

    类似于nextFree,这里是previousFree函数:

    func previousFree(from start: IndexPath) -> (Item, IndexPath)? {
        let sectionsToDrop = (dataSet.count - 1) - start.section
        let sections = dataSet.dropLast(sectionsToDrop).enumerated().reversed()
        for (section, store) in sections {
            let rows = store.items.enumerated().reversed().filter { $0.element.free }
            for (row, item) in rows where section != start.section || row < start.row {
                return (item, IndexPath(row: row, section: section))
            }
        }
        return nil
    }
    

    【讨论】:

    • 谢谢。您的解决方案确实略微提高了可读性和性能。我还注意到更改了一些命名,从而保持一致。此外,由于您的解决方案与我的非常相似,它告诉我我没有错过任何明显更简单的解决方案。我确实从一大堆 og 过滤器、reduce 和其他更高级别的函数开始,但很快就忘记了我实际在做什么,导致代码完全不可读。
    • 您可以做的是删除过滤器语句,并将row.element.isFree 添加到where 子句以获得更多性能提升。
    猜你喜欢
    • 2020-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-12
    • 1970-01-01
    • 2021-06-23
    • 2021-06-19
    相关资源
    最近更新 更多