【问题标题】:How do I concisely update a highly nested object model using swift?如何使用 swift 简洁地更新高度嵌套的对象模型?
【发布时间】:2020-04-21 19:38:22
【问题描述】:

我正在编写一个函数,该函数将挖掘对象层次结构的最深层次并更新特定值。作为参考,这是常规迭代的混乱程度:

func selectedStateUpdated(data: MyObject, tabId: String, rowId: String){
    for currIndex in 0..<self.model.data[0].data[0].filters.count{
        if(self.model.data[0].data[0].filters[currIndex].headerName == data.headerName){
            for tabIdx in 0..<model.data[0].data[0].filters[currIndex].data.count {
                if(self.model.data[0].data[0].filters[currIndex].data[tabIdx].id == tabId){
                    for rowItemIdx in 0..<self.model.data[0].data[0].filters[currIndex].data[tabIdx].data.count {
                        if(self.model.data[0].data[0].filters[currIndex].data[tabIdx].data[rowItemIdx].id == rowId){
                            self.model.data[0].data[0].filters[currIndex].data[tabIdx].data[rowItemIdx].isSelected.toggle()
                        }
                    }
                }
            }
        }
    }
}

深入挖掘我的数据模型并更新特定属性的最佳方法是什么?我正在尝试将驻留在此函数类中的model 对象作为全局对象进行更新。鉴于我的对象模型中的可迭代对象在 for 循环中是不可变的,有没有更好的方法来解决这个问题,同时确保我迭代到正确的

【问题讨论】:

标签: arrays swift loops


【解决方案1】:

本质上,这是一个数据结构问题。您正在对所有数据进行线性搜索,以查找具有特定 headerNametabIdrowId 的内容。它复杂、混乱且缓慢 (O(headerCount * tabCount * rowCount)!)

如果使用字典,这可能只是:

self.model.data[0].data[0]
    .filters[headerName]
    .data[tabId]
    .data[rowId]
    .isSelected
    .toggle()

如果数组必须保留,那么您可以通过将公共部分提取到命名局部变量来进行大量清理。反转 if 语句(在本例中,转换为 guard 语句`)还可以节省大量嵌套:

func selectedStateUpdated(headerName: String, tabId: String, rowId: String){
    let data = self.model.data[0].data[0] // TODO: name me better

    for currIndex in 0..<data.filters.count {
        let filter = data.filters[currIndex]
        guard filter.headerName == headerName else { return }

        for tabIdx in 0..<filter.data.count {
            let tab = filter.data[tabIdx]
            guard tab.id == tabId else { continue }

            for rowItemIdx in 0..< tab.data.count {
                let rowItem = tab.data[rowItemIdx]
                guard rowItem.id == rowId else { continue }

                self.model.data[0].data[0]
                    .filters[currIndex]
                    .data[tabIdx]
                    .data[rowItemIdx]
                    .isSelected
                    .toggle()
            }
        }
    }
}

可以通过使用zip 一次性获取索引和项目来进一步改进:

func selectedStateUpdated(headerName: String, tabId: String, rowId: String){
    let data = self.model.data[0].data[0] // TODO: name me better

    for (currIndex, filter) in zip(data.filters.indices, data.filters) {
        guard filter.headerName == headerName else { return }

        for (tabIdx, tab) in zip(filter.data.indices, filter.data) {
            guard tab.id == tabId else { continue }

            for (rowItemIdx, rowItem) in zip(tab.data.indices, tab.data) {
                guard rowItem.id == rowId else { continue }

                self.model.data[0].data[0]
                    .filters[currIndex]
                    .data[tabIdx]
                    .data[rowItemIdx]
                    .isSelected
                    .toggle()
            }
        }
    }
}

【讨论】:

    【解决方案2】:

    当你说“.id == tabId”时,你所做的基本上是一个过滤函数。这段代码非常混乱。但我想我设法弄清楚了:

    func selectedStateUpdated(data: [MyObject], tabId: String, rowId: String) {
    
        let filteredResult = self.model.data[0].data[0].filters
            .filter({$0.headerName == data.headerName &&
                $0.data.filter({$0.id == tabId}) &&
                $0.data.filter({$0.id == tabId &&
                    $0.data.filter({$0.id == rowId})
                })
            })
    
        if filteredResult.count > 0 {
            filteredResult.first!.isSelected.toggle()
        }
    }
    

    【讨论】:

    • 有趣的方法。这种方法是否允许我有效地将所有 isSelected 值也设置为 false?
    • 是的,如果你删除最后一行的 first! 并循环遍历它
    猜你喜欢
    • 2014-12-23
    • 1970-01-01
    • 1970-01-01
    • 2011-04-23
    • 1970-01-01
    • 2020-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多