1

how it is possible to sort an array by multiple conditions.

struct UserInformationModel: Identifiable, Hashable {
    
    let id = UUID()
    var isVip: Bool
    let userIsMale: Bool
    let userName: String
    let age: Int
    let userCountry: String
    let countryIsoCode: String
    let uid: String
    
}

And the view model contain the code:

class GetUserInformationViewModel: ObservableObject {
    
    @Published var allUsers = [UserInformationModel]()

 fun sortmyarray(){
   
  self.allUsers = self.allUsers.sorted(by: {$0.isVip && !$1.isVip})

}

how its possible to sort first the vip users, and then sort by age and then country?

2
  • 1
    You've answer the question for yourself. That's exactly what you are supposed to do. Commented Dec 8, 2020 at 9:12
  • how? how can i include multiple conditions in sort? as i said i want first vip users, then sort again with age and then sort again with country. Commented Dec 8, 2020 at 9:13

2 Answers 2

4

Here is a simple way to sort on multiple properties (I have assumed a sort order here for each property since it isn't mentioned in the question)

let sorted = users.sorted {
    if $0.isVip == $1.isVip {
        if $0.age == $1.age {
            return $0.userCountry < $1.userCountry
        } else {
            return $0.age < $1.age
        }
    }
    return $0.isVip && !$1.isVip
}

If the above is the natural sort order for the type then you could let the type implement Comparable and implement the < func

struct UserInformationModel: Identifiable, Hashable, Comparable {
    //properties removed for brevity 

    static func < (lhs: UserInformationModel, rhs: UserInformationModel) -> Bool {
        if lhs.isVip == rhs.isVip {
            if lhs.age == rhs.age {
                return lhs.userCountry < rhs.userCountry
            } else {
                return lhs.age < rhs.age
            }
        }
        return lhs.isVip && !rhs.isVip
    }
}

and then the sorting would be

let sorted = users.sorted()
Sign up to request clarification or add additional context in comments.

2 Comments

Why not simply sorted() after conforming to Comparable?
Btw if you need descending sorted(by: >)
2

Use tuples.

allUsers.sorted {
  ($1.isVip.comparable, $0.age, $0.userCountry)
  <
  ($0.isVip.comparable, $1.age, $1.userCountry)
}
public extension Bool {
  /// A way to compare `Bool`s.
  ///
  /// Note: `false` is "less than" `true`.
  enum Comparable: CaseIterable, Swift.Comparable {
    case `false`, `true`
  }

  /// Make a `Bool` `Comparable`, with `false` being "less than" `true`.
  var comparable: Comparable { .init(booleanLiteral: self) }
}

extension Bool.Comparable: ExpressibleByBooleanLiteral {
  public init(booleanLiteral value: Bool) {
    self = value ? .true : .false
  }
}

5 Comments

Instead of making booleans comparable, I would prefer using $0.isVip ? 1 : 0 which is much simpler and more generic when different boolean orderings are needed.
Nah, that’d seem natural for people who programmed in the 80s, but it’s archaic. We have types now.
Since booleans have no natural ordering, using a specific type to make them ordered is a bit strange.
Totally agree. I haven’t thought of a better solution than the structured documentation in this type yet. I’m not okay with converting Bools to types that have more than two cases, but I welcome a better idea!
+1 for the tuple solution. Also found an article here (sarunw.com/posts/…) outlining the same approach. Worked for my use case.

Your Answer

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