高效Swift数组比较

Efficient Swift Array Comparison

struct Area {
var name: String
var isSelected: Bool
}

我有两个列表:

我想做的是创建一个新的区域列表,其中包含两个列表中的项目,但如果列表一中的元素在列表二中,我想将 isSelected 属性 更新为 true。

我写了当前的方法,但它有缺陷且效率低下:

private func didGetCurrentUserSession(_ usersAreas: [Area]?, allAreas: [Area]){
        guard let usersAreas = usersAreas else {return}
        var newAreasList = [Area]()
        for area in allAreas {
            for userArea in usersAreas {
                if userArea.name == area.name {
                    newAreasList.append(Area(name: area.name, isSelected: true))
                    break
                }
            }
            newAreasList.append(Area(name: area.name, isSelected: false))
        }

        _loadingAreas.onNext(false)
        _areas.onNext(newAreasList)
    }

如有任何帮助,我们将不胜感激。更愿意使用非常 Swifty 的方法来完成此操作。

两种选择:对两个数组进行排序,或将一个数组转换为字典以便快速查找。不管你做什么,把它变成一个通用方法。

让我们获取用户区域的名称:

let userAreaNames = Set((usersAreas ?? []).map { [=10=].name })

映射其他区域

let newAreas = allAreas.map { area in
   return Area(
       name: area.name,
       isSelected: userAreaNames.contains(area.name)
   )
}

首先对数组进行排序以提高效率。

目前您的代码中的主要缺陷是错误的选定区域被附加到您的新数组,即使该区域的真实选定版本已经被附加。尝试这样的事情:

private func didGetCurrentUserSession(_ usersAreas: [Area]?, allAreas: [Area]){
    guard let usersAreas = usersAreas else {return}
    var newAreasList = [Area]()
    var selected = Bool()
    for area in allAreas {
        for userArea in usersAreas {
            if userArea.name == area.name {
                newAreasList.append(Area(name: area.name, isSelected: true))
                selected = true
                break
            }
        }
        if selected == false {
            newAreasList.append(Area(name: area.name, isSelected: false))
        } else {
            selected = false
        }
    }

    _loadingAreas.onNext(false)
    _areas.onNext(newAreasList)
}

Sulthan 的回答很好,但是你的警卫声明使得他的设置过于复杂。相反,只需将构造更简单的集合放入捕获列表即可。

let newAreas = allAreas.map { [usersAreaNames = Set( usersAreas.map(\.name) )] in
  Area(
    name: [=10=].name,
    isSelected: usersAreaNames.contains([=10=].name)
  )
}