简体   繁体   中英

How to define an ordered Map/Set with a runtime-defined comparator?

This is similar to How do I use a custom comparator function with BTreeSet? however in my case I won't know the sorting criteria until runtime. The possible criteria are extensive and can't be hard-coded (think something like sort by distance to target or sort by specific bytes in a payload or combination thereof). The sorting criteria won't change after the map/set is created.

The only alternatives I see are:

  • use a Vec , but log(n) inserts and deletes are crucial
  • wrap each of the elements with the sorting criteria (directly or indirectly), but that seems wasteful

This is possible with standard C++ containers std::map / std::set but doesn't seem possible with Rust's BTreeMap / BTreeSet . Is there an alternative in the standard library or in another crate that can do this? Or will I have to implement this myself?


My use-case is a database-like system where elements in the set are defined by a schema, like:

Element {
    FIELD x: f32
    FIELD y: f32
    FIELD z: i64

    ORDERBY z
}

But since the schema is user-defined at runtime, the elements are stored in a set of bytes ( BTreeSet<Vec<u8>> ). Likewise the order of the elements is user-defined. So the comparator I would give to BTreeSet would look like |a, b| schema.cmp(a, b) |a, b| schema.cmp(a, b) . Hard-coded, the above example may look something like:

fn cmp(a: &Vec<u8>, b: &Vec<u8>) -> Ordering {
    let a_field = self.get_field(a, 2).as_i64();
    let b_field = self.get_field(b, 2).as_i64();
    a_field.cmp(b_field)
}

Would it be possible to pass the comparator closure as an argument to each node operation that needs it? It would be owned by the tree wrapper instead of cloned in every node.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM