Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested Sort in Struct Array in Swift 5

Here its my model looks like

struct ContactModel{
    var alphabet: String
    var users: [UserModel]
}

struct UserModel{
    var firstname: String
    var lastname: String
}

Using sort alphabetically sorting working fine here Is the code:

contactArray.sort{ $0.alphabet < $1.alphabet }

Now, I want to sort ascending or descending order on bases of UserModel firstname I try with nested sorting but giving me different errors like

Comparable and Binary operator '<' cannot be applied to two '[UserModel]' operands

I search on StackOverflow regarding this but haven't find nested sorting and operands error solution.

I tried this way

let sortedStudents = contactArray.sorted { (lhs: ContactModel, rhs: ContactModel) -> Bool in
                let users1 = lhs.users.sorted(by: {
                    $0.firstname.lowercased() < $1.firstname.lowercased()
                })
                let users2 = rhs.users.sorted(by: {
                    $0.firstname.lowercased() < $1.firstname.lowercased()
                })
                
                return users1 < users2
            }

But its not working. The only problem here that I am not able to do nested sort here want to sort firstname of UserModel and the We have ContactModel Array

var contactArray = [ContactModel](){
        didSet{
            
            contactArray.sort{ $0.alphabet < $1.alphabet } //Simple Sort working fine.
            
            let sortedStudents = contactArray.sorted { (lhs: ContactModel, rhs: ContactModel) -> Bool in
                let users1 = lhs.users.sorted(by: {
                    $0.firstname.lowercased() < $1.firstname.lowercased()
                })
                let users2 = rhs.users.sorted(by: {
                    $0.firstname.lowercased() < $1.firstname.lowercased()
                })
                
                return users1 < users2
            }
            
            self.tableView.reloadData()
        }
    }

Array Contains this

 func getAllContacts() -> [ContactModel]{
        return [
            ContactModel(alphabet: "B", users: [
                UserModel(firstname: "Bhaswar", lastname: "Patel"),
                UserModel(firstname: "Bunty", lastname: "Patel")
            ]),
            ContactModel(alphabet: "N", users: [
                UserModel(firstname: "Nilesh", lastname: "Darji")
            ]),
            ContactModel(alphabet: "Y", users: [
                UserModel(firstname: "Yogesh", lastname: "Patel"),
                UserModel(firstname: "Yash", lastname: "Patel")
            ])
        ]
    }

Results:

Alphabetic section sorting working fine need to sort users now using firstname for this Yash is comes first then Yogesh

Any suggestion appreciated. Thanks!

like image 430
Yogesh Patel Avatar asked Jun 12 '26 20:06

Yogesh Patel


1 Answers

The code below is sorting the ContactModel array based on the alphabet first. Then, it maps this sorted array to a new array where the UserModel array is sorted as well.

contactArray.sort { $0.alphabet < $1.alphabet }
let fullySorted = contactArray.map( { ContactModel(alphabet: $0.alphabet, users: $0.users.sorted { $0.firstname < $1.firstname }) } )

The map and sort functions could also be swapped, i.e. first mapping to a new array and then sorting based on the alphabet. The original array:

var contactArray = [
    ContactModel(alphabet: "B", users: [
        UserModel(firstname: "Bhaswar", lastname: "Patel"),
        UserModel(firstname: "Bunty", lastname: "Patel")
    ]),
    ContactModel(alphabet: "N", users: [
        UserModel(firstname: "Nilesh", lastname: "Darji")
    ]),
    ContactModel(alphabet: "Y", users: [
        UserModel(firstname: "Yogesh", lastname: "Patel"),
        UserModel(firstname: "Yash", lastname: "Patel")
    ])
]

will become (Yash and Yogesh are now alphabetically ordered):

var contactArray = [
    ContactModel(alphabet: "B", users: [
        UserModel(firstname: "Bhaswar", lastname: "Patel"),
        UserModel(firstname: "Bunty", lastname: "Patel")
    ]),
    ContactModel(alphabet: "N", users: [
        UserModel(firstname: "Nilesh", lastname: "Darji")
    ]),
    ContactModel(alphabet: "Y", users: [
        UserModel(firstname: "Yash", lastname: "Patel"),
        UserModel(firstname: "Yogesh", lastname: "Patel")
    ])
]

If there would be another ContactModel with alphabet = "A", then this would've been the first one in the contactArray.

You could even reduce it to a single line of code if you really want. However, I wouldn't recommend it because sorting, and mapping can become hard to read quite easily for people that aren't familiar with it.

// Single line of code solution (I wouldn't recommend this because of readability)
let fullySorted = contactArray.sorted { $0.alphabet < $1.alphabet }.map( { ContactModel(alphabet: $0.alphabet, users: $0.users.sorted { $0.firstname < $1.firstname }) } )
like image 99
Bjorn Avatar answered Jun 14 '26 18:06

Bjorn



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!