How to sort a composite struct with string and number?

Viewed 47

So this is my struct. As you can see it's a composite struct (string and number/Decimal)

use rust_decimal::prelude::*;

#[derive(Deserialize, Serialize, Clone, Eq, Ord, PartialEq, PartialOrd)]
pub struct Row {
    pub acc_code: String,
    pub acc_type: String,
    pub acc_name: String,
    pub before: Decimal,
    pub total: Decimal,
    pub after: Decimal,
}

and this is how I sort an array (Vector) of this struct. I use the sort_by_key() method for vector:

   let sort_by = Some("acc_code");
   let container: Vec<Row> = vec![];

    // sorting
    match view_options.sort_by {
        Some(sort_by) => {
            container.sort_by_key(|r| match sort_by.as_ref() {
                "acc_code" => r.acc_code.clone(),
                "acc_type" => r.acc_type.clone(),
                "acc_name" => r.acc_name.clone(),
                "before" => r.before.to_string(), // this is  the source of the problem
                "after" => r.after.to_string(), // I can only use one of the type
                "total" => r.total.to_string(), // either string or number here
                _ => r.acc_code.clone(),
            });
        }
        None => {}
    }

this works as long as it only sort field with string type (acc_code, acc_type or acc_name).

If you sort the number field (like total, after or before), it only sort the first character of that number (since it is converted to a string), eg: [1000, 4, 500, 6]. Rust only sees the first character of that number and doesn't consider the rest

I had to use string for sort_by_key to work since it requires unified output types. So either I convert the number into string or convert the string into number. So how do I give a numerical "value" into a string so it will sort properly across any field ?

1 Answers

Instead of using sort_by_key(), use sort_by():

container.sort_by(|a, b| match sort_by.as_ref() {
    "acc_code" => a.acc_code.cmp(&b.acc_code),
    "acc_type" => a.acc_type.cmp(&b.acc_type),
    "acc_name" => a.acc_name.cmp(&b.acc_name),
    "before" => a.before.cmp(&b.before),
    "after" => a.after.cmp(&b.after),
    "total" => a.kredit.cmp(&b.kredit),
    _ => a.acc_code.cmp(&b.acc_code),
});
Related