rust-lang / rust

Empowering everyone to build reliable and efficient software.

Home Page:https://www.rust-lang.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

BinaryHeap flexibility, BuildComparator

leonardo-m opened this issue · comments

In D language when you create a binary heap you can optionally specify the comparison function:

void main() {
    import std.stdio, std.container;
    auto heap1 = [10, 2, 5, 3].heapify;
    writeln(heap1); // Output: [10, 5, 3, 2]
    auto heap2 = [10, 2, 5, 3].heapify!q{b < a};
    writeln(heap2); // Output: [2, 3, 5, 10]
}

This is handy. Similar code in Rust:

fn main() {
    use std::collections::BinaryHeap;
    let heap1: BinaryHeap<_> = [10, 2, 5, 3].iter().cloned().collect();
    println!("{:?}", heap1); // [10, 3, 5, 2]
}

If you just have to reverse the ordering (a min-heap) you can sometimes wrap your items with this:

https://docs.rs/revord/0.0.2/revord/struct.RevOrd.html

But in general the cmp function can be more complex (or it can involve just one field of each item). Currently to solve this problem you need to write a lot of boilerplate code, a newtype and implement the four Eq/Ord traits on it (but a binary heap doesn't need to test the equality of the the items).

So can we add something more handy to BinaryHeap to specify a different comparison function?

A comment by cuviper:

To support collect, I think you'd have to incorporate it into the type, just like HashMap<K, V, S: BuildHasher>. So this would have some kind of BuildComparator, and it could be added without a breaking change by defaulting to a MaxComparator.

The general case might still feel like annoying boiler plate with what I suggested, having to implement a BuildComparator and corresponding Comparator. But maybe a few provided basics can ease most cases, like MaxComparator, MinComparator, and generally FnMutComparator.

I would love to support this better. That D code is really slick! I believe this is going to require an RFC in which someone proposes a concrete API for how this would work in Rust. The BuildComparator approach sounds promising.