1

I have an array of messages that I want to sort by whether they are unread or not, and their time stamp. These messages will be displayed in a TableView.

All unread messages should be displayed at the top, and then sorted by their timestamp.

Below is what I have right now; but what seems to be happening is that the items are displayed only by time stamp, without sorting them by unread at the top and then unread messages after.

let channelsSortedByUnreadFirst = dataStore.messages.sorted { $0.isUnread == true && $1.isUnread == false }
let timeSortedItems = channelsSortedByUnreadFirst.sorted(by: { $0.timeStamp > $1.timeStamp })
messagesTableViewSection.items = timeSortedItems

How do I sort these messages by both isUnread and timeStamp?

3 Answers 3

3

Bool does not conform to Comparable. What you need is to extend Bool type and convert its value to a type that conforms to Comparable like integer 0 or 1 and sort it using its value:


extension Bool {
    var value: Int { self ? 1 : 0 }
}

true.value    // 1
false.value   // 0

Now you can use the boolean value when sorting your collection:

let channelsSorted = dataStore.messages.sorted { ($0.isUnread.value, $0.timeStamp) > ($1.isUnread.value, $1.timeStamp) }
Sign up to request clarification or add additional context in comments.

3 Comments

Wait, what? You can compare tuples and it evaluates the first item as a primary sort key and the 2nd sort key?!?
Very cool. I somehow missed that. (Voted)
1

Another way using Swift Algorithms stablePartition(by:):

import Algorithms

var messages = dataStore.messages
messages.sort { $0.timeStamp > $1.timeStamp }
let firstReadIndex = messages.stablePartition { !$0.isUnread }

Comments

1

Another Way that might be more intuitive but uses multiple passes.

print(messages.filter(\.isUnread).sorted { $0.timeStamp > $1.timeStamp } + messages.filter { !$0.isUnread })

3 Comments

I think read messages should also be sorted
"All unread messages should be displayed at the top, and then sorted by their timestamp." Its kind of ambiguous language. meh
I agree, and it would be easy to add should OP feel the need :)

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.