3

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
5
  • 1
    The issue is that optionals cannot be compared by default using the <,> operators. Either define the return value yourself for the case when either/both startTimes are nil or change the type of startTime to Int. Commented Nov 13, 2017 at 0:00
  • Ah, thank you, David! Commented Nov 13, 2017 at 0:15
  • 1
    @FlatDog All optional fields is a pretty big red flag. Are you sure it makes sense for a session to not have a start or end time, name, or anything else? Commented Nov 13, 2017 at 0:20
  • Yeah, I'm looking into changing that, thanks @Alexander. Commented Nov 13, 2017 at 0:23
  • 1
    Since Swift4 (I think), comparing optionals is no more possible. 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 Commented Nov 15, 2017 at 15:27

4 Answers 4

4

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
}

})
Sign up to request clarification or add additional context in comments.

Comments

2

You should access the fields directly and not through subscripts.

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

1 Comment

For those upvoting, keep in mind that this code won't compile since startTime is an optional.
1

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

Comments

0

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)

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.