Search code examples
sortingrustcollections

How to Sort Vector of Structs by Chronos DateTime Field?


I have this struct

pub struct Items {
    pub symbol: String,
    pub price: f64,
    pub date: DateTime<Utc>,
}

I have a vector of these structs. I would like to sort them by date. How would I go about doing that? I tried deriving PartialEq, Ord, Eq, etc... but Rust complains about the float fields.


Solution

  • The easiest way is to use one of the provided sort functions implemented for Vec like sort_by, sort_by_key, or sort_by_key_cached.

    // Using sort_by
    foo_items.sort_by(|a, b| a.date.cmp(&b.date));
    
    // Using sort_by_key
    foo_items.sort_by_key(|x| x.date);
    
    // Using sort_by_key_cached (Faster if key is very large)
    foo_items.sort_by_cached_key(|x| x.date);
    

    And don't forget you always have the option to manually implement traits that are normally derived.

    use std::cmp::Ordering;
    
    impl PartialEq for Items {
        fn eq(&self, other: &Self) -> bool {
            // idk what symbol is, but use it anyway
            self.symbol == other.symbol && self.date == other.date
        }
    }
    
    impl Eq for Items {}
    
    impl PartialOrd for Items {
        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
            self.date.partial_cmp(&other.date)
        }
    }
    
    impl Ord for Items {
        fn cmp(&self, other: &Self) -> Ordering {
            self.date.cmp(&other.date)
        }
    }
    

    Edit: I just wanted to add an extra note here for anyone who is viewing this.

    Firstly, these sorting functions are implemented for slices, not Vec (the example doesn't change though). When used, Vec<T>'s implementation of DerefMut is implicitly called to get a &mut [T] that implements the sorting function. This means that you can sort any data structure you can get a mutable slice of.

    Second, using sort_unstable is almost always preferable to sort (there are also variants for _by, and _by_key). To quote to documentation:

    Sorts the slice, but might not preserve the order of equal elements.

    This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not allocate), and O(n * log(n)) worst-case.

    Current implementation
    The current algorithm is based on pattern-defeating quicksort by Orson Peters, which combines the fast average case of randomized quicksort with the fast worst case of heapsort, while achieving linear time on slices with certain patterns. It uses some randomization to avoid degenerate cases, but with a fixed seed to always provide deterministic behavior.

    It is typically faster than stable sorting, except in a few special cases, e.g., when the slice consists of several concatenated sorted sequences.