Swift sort array by Bool value and TimeStamp

Viewed 200

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

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) }

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 }

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

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