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.