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

I have two lists:

  • List One: It has the full list of Areas.
  • List Two: It has a subset of Areas from List One the user has selected (but selected state is not set)

What I want to do is to create a new list of Areas that has items from both lists but if an element from List One is in List Two I want to update the isSelected property to true.

I wrote the current method but its flawed and inefficient:

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)
    }

Any help with this would be highly appreciated. Would prefer to accomplish this by using very Swifty approach.

4 Answers 4

4

Let's get names of user areas:

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

map the other areas

let newAreas = allAreas.map { area in
   return Area(
       name: area.name,
       isSelected: userAreaNames.contains(area.name)
   )
}
Sign up to request clarification or add additional context in comments.

5 Comments

??, not ||! usersAreas.map { Set( $0.map(\.name) ) } is more meaningful though.
@Jessy thanks for the ?? fix :) Lots of Javascript coding recently. I actually prefer using $0.name over key paths. Both are possible. I think that removing the optional makes more sense here than using Optional.map.
Not preferring key paths is bad because $0 is worse than \ and >= 3 spaces are worse than zero.
@Jessy I wanted to verify you statement but there is no map function that would accept a key path. That means you are probably using an extension which adds that using the closure map. And that means it cannot have better performance. I don't understand your statement about spaces.
Not sure what you’re saying there. Maybe you’re not using Swift 5.2? github.com/apple/swift-evolution/blob/master/proposals/…
2

Two choices: Sort both arrays, or turn one into a dictionary for fast lookup. And whatever you do, turn it into a generic method.

2 Comments

No need for a generic if the functionality won't be ever used with a different type.
Thank you for your fast response. I have chosen to go with Sulthans answer. It's a very clean and Swift approach.
2

Sort the arrays first to increase efficiency.

The main flaw in your code at the moment is that a false selected area is appended to your new array even if a true selected version of that same area has already been appended. Try something like this instead:

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 Comments

Hi, Simba thank you very much for your answer. You identified the flaw to the point. I have chosen to go with the answer presented by @Sulthan because its a lot cleaner and more swifty.
No problem - I also prefer Sulthan's answer!
0

Sulthan's answer is good, but your guard statement makes it so that his set is overcomplicated. Instead, just put the more simply-constructed set into the capture list.

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.