Sorting Struct array in Swift 4

Viewed 3264

I've got the below struct and would like to sort the items within sessions by startTime field. I'm completely lost on how to do this.

I tried:

let sortedArray = sessionsData?.items.sorted{ ($0["startTime"] as! String) < ($1["startTime"] as! String) }

but that just gives me an error about no subscript members?

Any pointers would really be appreciated, thank you.

public struct sessions: Decodable {
  let status: String?
  let start: Int?
  let count: Int?
  let items: [sessionInfo]?
  let itemsCount: Int?
  let multipart: Bool?
  let startTime: Int?
  let endTime: Int?
}


public struct sessionInfo: Decodable {
  let name: String?
  let datalist: String?
  let sessionType: Int?
  let status: Int?
  let backupType: Int?
  let startTime: Int?
  let endTime: Int?
  let owner: String?
  let numOfErrors: Int?
  let numOfWarnings: Int?
  let flags: Int?
}

I tried the below, but get an error:

var sortedArray = sessionsData?.items?.sorted(by: { (lhs, rhs) -> Bool in
        return lhs.startTime < rhs.startTime
    })

error:

Binary operator '<' cannot be applied to two 'Int?' operands
4 Answers

Try below code, it sorts the struct in asc order but it pushes nil timestamps to bottom. if you want nil timestamps to be at top, make all nil checks in below code to return opposite of what i return in below code.

var sortedArray = sessionsData?.items?.sorted(by: { (lhs, rhs) -> Bool in

if let lhsTime = lhs.startTime, let rhsTime = rhs.startTime {
    return lhs.startTime < rhs.startTime
}

if lhs.startTime == nil && rhs.startTime == nil {
    // return true to stay at top
    return false
}

if lhs.startTime == nil {
    // return true to stay at top
    return false
}

if rhs.startTime == nil {
    // return false to stay at top
    return true
}

})

You should access the fields directly and not through subscripts.

let sortedArray = sessionsData?.items.sorted(by: {$0.startTime < $1.startTime})

You could write this (tested in playground) :

var sortedArray = sessionsData?.items?.sorted(by: { (lhs, rhs) -> Bool in return (lhs.startTime ?? 0) < (rhs.startTime ?? 0) })

If one is optional, you do not crash, even though result of comparison is meaningless

You have default High Order Function for sorting the struct array in ascending and descending order

Example

let roster: [TeamMember] = [.init(id: 1, name: "Abishek", age: 19),
                           .init(id: 2, name: "Dinesh", age: 22),
                           .init(id: 3, name: "Praveen", age: 24),
                           .init(id: 4, name: "Sam", age: 25),
                           .init(id: 5, name: "David", age: 21)]


let descendingSorted = roster.sorted{$0.name > $1.name} // for descending order
let ascendingSorted = roster.sorted{$0.name < $1.name} // for ascending order
print(descendingSorted)
print(ascendingSorted)

Your Output

// for descending order
[TeamMember(id: 4, name: "Sam", age: 25.0),
 TeamMember(id: 3, name: "Praveen", age: 24.0),
 TeamMember(id: 2, name: "Dinesh", age: 22.0),
 TeamMember(id: 5, name: "David", age: 21.0),
 TeamMember(id: 1, name: "Abishek", age: 19.0)]

// for ascending order
[TeamMember(id: 1, name: "Abishek", age: 19.0),
 TeamMember(id: 5, name: "David", age: 21.0),
 TeamMember(id: 2, name: "Dinesh", age: 22.0),
 TeamMember(id: 3, name: "Praveen", age: 24.0),
 TeamMember(id: 4, name: "Sam", age: 25.0)]

And we have another one method for sorting is SortComparator. we sort the result based on ComparisonResult

let descendingSorted1 = roster.sorted { teamMember1, teamMember2 in
  return teamMember1.name.compare(teamMember2.name) == .orderedDescending
} // for descending order
let ascendingSorted1 = roster.sorted{ teamMember1, teamMember2 in
  return teamMember1.name.compare(teamMember2.name) == .orderedAscending
} // for ascending order
print(descendingSorted1)
print(ascendingSorted1)
Related