Эффективное сравнение массивов Swift - PullRequest
0 голосов
/ 26 апреля 2020
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)
    }

Любая помощь с этим будет высоко оценена. Я бы предпочел выполнить sh, используя очень Swifty подход.

Ответы [ 4 ]

4 голосов
/ 26 апреля 2020

Давайте получим названия пользовательских областей:

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

отобразим другие области

let newAreas = allAreas.map { area in
   return Area(
       name: area.name,
       isSelected: userAreaNames.contains(area.name)
   )
}
2 голосов
/ 26 апреля 2020

Сортируйте массивы в первую очередь, чтобы повысить эффективность.

Основной недостаток вашего кода на данный момент заключается в том, что ложно выбранная область добавляется к вашему новому массиву, даже если истинно выбранная версия этой же области уже имеет был добавлен. Попробуйте что-то вроде этого:

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)
}
2 голосов
/ 26 апреля 2020

Два варианта: сортировать оба массива или превратить один в словарь для быстрого поиска. И что бы вы ни делали, включите его в общий метод c.

0 голосов
/ 26 апреля 2020

Ответ Султана хорош, но ваше охранное заявление делает его таким, что его сет слишком усложнен. Вместо этого просто поместите более простой набор в список захвата.

let newAreas = allAreas.map { [usersAreaNames = Set( usersAreas.map(\.name) )] in
  Area(
    name: $0.name,
    isSelected: usersAreaNames.contains($0.name)
  )
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...