-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New lookup functions on BTreeMap/Set #49638
Comments
Note that, if desperate, the API of BTreeSet is currently powerful enough for a user to implement these on their own: use std::collections::{Bound, BTreeSet};
fn get_lt<'a, T: Ord>(set: &'a BTreeSet<T>, value: &T) -> Option<&'a T> {
set.range((Bound::Unbounded, Bound::Excluded(value))).next_back()
}
fn get_le<'a, T: Ord>(set: &'a BTreeSet<T>, value: &T) -> Option<&'a T> {
set.range((Bound::Unbounded, Bound::Included(value))).next_back()
}
fn get_gt<'a, T: Ord>(set: &'a BTreeSet<T>, value: &T) -> Option<&'a T> {
set.range((Bound::Excluded(value), Bound::Unbounded)).next()
}
fn get_ge<'a, T: Ord>(set: &'a BTreeSet<T>, value: &T) -> Option<&'a T> {
set.range((Bound::Included(value), Bound::Unbounded)).next()
}
fn main() {
let set = vec![1, 4, 6].into_iter().collect::<BTreeSet<_>>();
assert_eq!(get_lt(&set, &0), None);
assert_eq!(get_lt(&set, &1), None);
assert_eq!(get_lt(&set, &2), Some(&1));
assert_eq!(get_lt(&set, &7), Some(&6));
assert_eq!(get_le(&set, &0), None);
assert_eq!(get_le(&set, &1), Some(&1));
assert_eq!(get_le(&set, &2), Some(&1));
assert_eq!(get_le(&set, &7), Some(&6));
assert_eq!(get_gt(&set, &7), None);
assert_eq!(get_gt(&set, &6), None);
assert_eq!(get_gt(&set, &5), Some(&6));
assert_eq!(get_gt(&set, &0), Some(&1));
assert_eq!(get_ge(&set, &7), None);
assert_eq!(get_ge(&set, &6), Some(&6));
assert_eq!(get_ge(&set, &5), Some(&6));
assert_eq!(get_ge(&set, &0), Some(&1));
} (I only say this as a matter of fact; not meaning to imply that there is no point to adding the feature to std. My opinion on that is neutral) |
That's really cool! Thanks for sharing 😄 Does it have the same performance characteristics of a |
In theory it should have the same performance characteristics, if the implementation of Even if it turns out that |
Here's a better API: /// Returns the highest element whose key is below the given bound.
fn upper_bound<Q>(&self, bound: Bound<&Q>) -> Option<&V>
where
K: Borrow<Q>,
Q: Ord + ?Sized;
/// Returns the lowest element whose key is above the given bound.
fn lower_bound<Q>(&self, bound: Bound<&Q>) -> Option<&V>
where
K: Borrow<Q>,
Q: Ord + ?Sized; |
That is a much improved API 😄 |
@rustbot claim |
Hi, are you still working on this issue @Prabhakar-17? |
@Alexendoo sorry, didn't find time to work on this one. if someone else is willing to pick it up please go ahead otherwise I will have time next weekend. |
Looks like this still hasn't been implemented but was looking into similar functionality recently. IIUC, given a key query // Could use a better name
pub struct Neighbors<'a, K: 'a, V: 'a> {
pub lesser: Option<(&K, &V)>,
pub equal: Option<(&K, &V)>,
pub greater: Option<(&K, &V)>,
};
pub fn neighbors<Q>(&self, key: &Q) -> Neighbors<K, V>
where
K: Borrow<Q> + Ord,
Q: Ord + ?Sized; |
@GodTamIt I'd love to have what you suggested in the problem I'm trying to solve. Otherwise, I'm forced to do 2 separate calls to get the lesser and the greater element respectively. |
Happy to work on an implementation if there isn't too much opposition to it here |
Hmm, a struct with three options makes me feel like its semantics are cluttered, though I don't see any obvious subsetting that would help. I wonder if it could make sense to have some sort of cursor/finger API that would make it easy to get the next/previous elements from a position... |
I thought about this kind of API but there were two main issues that would need to be sorted out:
|
I would recommend modeling it based on the |
Just tossing an idea: I wonder if the cursor API can be combined with the existing Entry API so that the Cursor will return something like the |
That's not true: each node in the tree has a pointer to its parent, so you don't need to track this in the cursor itself.
I would recommend mirroring the API of |
@rustbot release-assignment |
For completeness: There was an ACP rust-lang/libs-team#141 and there is a nightly feature |
The current function
get
attempts to find an exact key match; if it fails, it returnsNone
. I propose the addition of four variants:get_lt
finds the greatest(key, element)
in the map/set that is less than the given key.get_lte
returns the lookup key and element in the map if present, otherwise returning the next smallest key and element.get_gt
finds the smallest(key, element)
in the map/set that is greater than the given key.get_gte
looks up the key; if present, returns it and the element, if not, returns the next largest key and element.The specific use case that prompted this:
I'm working on a toy Smalltalk implementation. One of the implementation methods is "given an object pointer, find the next object pointer that is an instance of of the class." Given a value
instances: BTreeSet<Pointer>
, the implementation is simplyget_gt(obj_ptr)
.The text was updated successfully, but these errors were encountered: