topset/heap.rs
1use std::cmp::Ordering;
2use std::fmt::{Debug, Formatter};
3use std::mem;
4use crate::TopSet;
5
6impl<X,C> TopSet<X,C>
7 where C: Fn(&X,&X) -> bool
8{
9 /// Creates a new top set with a selecting closure.
10 ///
11 /// The size corresponds to the maximum number of items
12 /// allowed in the top set.
13 ///
14 /// The function `C` is the challenge to decide if an
15 /// element beats another one and so takes its place.
16 /// It should corresponds to a total ordering.
17 ///
18 /// If the first one beats the second one then `true` should
19 /// be returned and if `false' corresponds to the case when
20 /// the second item beats the first one.
21 /// This function should always returns the same result
22 /// when dealing with the same items or results are unpredictable.
23 ///
24 /// # Example
25 /// Collecting the 5 greatest integers is performed by using a
26 /// topset with `n = 5` and `beat = i32::gt`.
27 /// ```
28 /// # use topset::TopSet;
29 /// let mut topset = TopSet::new(5, i32::gt);
30 /// ```
31 pub fn new(n: usize, beat: C) -> Self
32 {
33 Self {
34 heap: Vec::with_capacity(n),
35 count: n,
36 beat
37 }
38 }
39
40 /// Creates a new top set with a selecting closure and an initial set of items.
41 ///
42 /// If the initial set contains more than `n` elements, only the `n` greatest ones
43 /// (according to `beat` challenging function) are stored.
44 ///
45 /// # Example
46 /// ```
47 /// # use topset::TopSet;
48 /// let mut topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3]);
49 /// assert_eq!( topset.pop(), Some(7));
50 /// assert_eq!( topset.pop(), Some(9));
51 /// assert_eq!( topset.pop(), None);
52 /// ```
53 pub fn with_init<I: IntoIterator<Item=X>>(n: usize, beat: C, init: I) -> Self
54 {
55 let mut top = Self::new(n, beat);
56 top.extend(init);
57 top
58 }
59
60 /// Check if the top set is empty
61 /// # Example
62 /// ```
63 /// # use topset::TopSet;
64 /// let mut topset = TopSet::new(2, u32::gt);
65 /// assert!( topset.is_empty() );
66 /// topset.extend( vec![7,5,6,9,4,2,3] );
67 /// assert!( ! topset.is_empty() );
68 /// ```
69 #[inline]
70 pub fn is_empty(&self) -> bool { self.heap.is_empty() }
71
72 /// Get the number of stored items.
73 ///
74 /// It never exceeds the predefined capacity
75 /// (the capacity does not grow by itself, only by calling [`Self::resize`]).
76 ///
77 /// # Example
78 /// ```
79 /// # use topset::TopSet;
80 /// let mut topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3] );
81 /// assert_eq!( topset.len(), 2 );
82 /// topset.pop();
83 /// assert_eq!( topset.len(), 1 );
84 /// ```
85 #[inline]
86 pub fn len(&self) -> usize { self.heap.len() }
87
88 /// Get the capacity of this top set
89 ///
90 /// The capacity limits the number of elements to keep.
91 /// This capacity could only change by calling [`resize`].
92 ///
93 /// # Example
94 /// ```
95 /// # use topset::TopSet;
96 /// let mut topset = TopSet::new(4, u32::gt);
97 /// assert_eq!( topset.capacity(), 4 );
98 /// assert_eq!( topset.len(), 0 );
99 /// ```
100 #[inline]
101 pub fn capacity(&self) -> usize { self.count }
102
103 /// Read access to the lowest item of the top set
104 ///
105 /// Notice that it actually returned the _lowest_ one and
106 /// so all the others are better (or equal) this one.
107 ///
108 /// To access to this _lowest_ element and removing it,
109 /// consider [`Self::pop`].
110 ///
111 /// # Example
112 /// ```
113 /// # use topset::TopSet;
114 /// let mut topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3] );
115 /// assert_eq!( topset.peek(), Some(&7) );
116 /// assert_eq!( topset.pop(), Some(7) );
117 /// assert_eq!( topset.peek(), Some(&9) );
118 /// ```
119 #[inline]
120 pub fn peek(&self) -> Option<&X>
121 {
122 self.heap.first()
123 }
124
125 /// Checks if an item will be inserted or not
126 ///
127 /// If it `true` is returned, it means that a call to [`Self::insert`]
128 /// will actually insert the candidate. If `false`, then the insertion
129 /// will be a non-op.
130 ///
131 /// Note that in any case the insertion is not done. See [`Self::insert`] to
132 /// perform the test and the insertion in one time.
133 ///
134 /// # Example
135 /// ```
136 /// # use topset::TopSet;
137 /// // this topset contains { 7, 9 }
138 /// let topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3] );
139 /// assert!( topset.is_candidate(&10) );
140 /// assert!( topset.is_candidate(&8) );
141 /// assert!( ! topset.is_candidate(&7) );
142 /// assert!( ! topset.is_candidate(&6) );
143 /// ```
144 #[inline]
145 pub fn is_candidate(&self, x: &X) -> bool {
146 self.heap.len() < self.count || self.beat(x, self.peek().unwrap())
147 }
148
149 /// Iterate over all the top selected items.
150 ///
151 /// The iterator is **not** sorted. A sorted iteration
152 /// could be obtained by iterative call to [`Self::pop`]
153 /// or by using [`Self::into_iter_sorted`].
154 ///
155 /// To get a vector with all elements, instead of using this
156 /// iterator, consider [`Self::into_vec`].
157 ///
158 /// # Example
159 /// ```
160 /// # use topset::TopSet;
161 /// // this topset contains { 7, 9 }
162 /// let topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3] );
163 /// let elts = topset.iter().cloned().collect::<Vec<_>>();
164 /// ```
165 #[inline]
166 pub fn iter(&self) -> impl Iterator<Item=&X>
167 {
168 self.heap.iter()
169 }
170
171 /// Gets all the top set elements in a vector.
172 ///
173 /// This vector is **not** sorted.
174 /// See [`Self::into_sorted_vec`] if a sorted result is expected.
175 ///
176 /// # Example
177 /// ```
178 /// # use topset::TopSet;
179 /// // this topset contains { 7, 9 }
180 /// let topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3] );
181 /// let elts = topset.into_vec();
182 /// ```
183 #[inline]
184 pub fn into_vec(self) -> Vec<X> { self.heap }
185
186 /// Insert a new item.
187 ///
188 /// If the top set is not filled (i.e. its length is less than its capacity),
189 /// the item is simply added and `None` is returned.
190 ///
191 /// If there is no more room, then one item should be rejected:
192 /// * if the new item is better than some already stored ones, it is added
193 /// and the removed item is returned
194 /// * if the new item is worse than all the stored ones, it is returned
195 ///
196 /// # Example
197 /// ```
198 /// # use topset::TopSet;
199 /// let mut topset = TopSet::new(2, u32::gt);
200 /// assert_eq!( topset.insert(7), None);
201 /// assert_eq!( topset.insert(8), None);
202 /// assert_eq!( topset.insert(9), Some(7));
203 /// assert_eq!( topset.insert(6), Some(6));
204 /// ```
205 pub fn insert(&mut self, mut x: X) -> Option<X>
206 {
207 if self.heap.len() < self.count {
208 // some room left, so nothing to remove
209 self.heap.push(x);
210 self.percolate_up(self.heap.len()-1);
211 None
212 } else {
213 // SAFETY: if the heap is empty when self.count != 0, then we fall
214 // in the previous if condition (so, here, get_unchecked is safe)
215 if self.count != 0 && self.beat(&x, unsafe { self.heap.get_unchecked(0) }) {
216 // put the greatest the deepest: the new one should be kept
217 mem::swap(&mut x, &mut self.heap[0]);
218 self.percolate_down(0);
219 }
220 Some(x)
221 }
222 }
223
224 /// Converts this topset into a sorted iterator
225 ///
226 /// Notice that the _lowest_ item of the top set is the
227 /// first one. The _greatest_ item is the last one.
228 ///
229 /// # Example
230 /// ```
231 /// # use topset::TopSet;
232 /// // this topset contains { 7, 9 }
233 /// let topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3] );
234 /// let mut iter = topset.into_iter_sorted();
235 /// assert_eq!( iter.next(), Some(7));
236 /// assert_eq!( iter.next(), Some(9));
237 /// assert_eq!( iter.next(), None);
238 /// ```
239 #[inline]
240 pub fn into_iter_sorted(self) -> crate::iter::IntoIterSorted<X,C> {
241 self.into()
242 }
243
244 /// Returns the topset in a sorted vector.
245 ///
246 /// The first element of the vector is the _lowest_ item of the top set
247 /// and the last one is the _greatest_ one.
248 ///
249 /// # Example
250 /// ```
251 /// # use topset::TopSet;
252 /// // this topset contains { 7, 9 }
253 /// let topset = TopSet::with_init(3, u32::gt, vec![1,2,7,4,7,5,6,9,4,2,3] );
254 /// assert_eq!( topset.into_sorted_vec(), vec![7,7,9]);
255 /// ```
256 pub fn into_sorted_vec(mut self) -> Vec<X>
257 where X:PartialEq
258 {
259 self.heap.sort_unstable_by(|a,b| {
260 if *a == *b {
261 Ordering::Equal
262 } else if (self.beat)(a,b) {
263 Ordering::Greater
264 } else {
265 Ordering::Less
266 }
267 });
268 self.heap
269 }
270
271 /// Clears the binary heap, returning an iterator over the removed elements in arbitrary order.
272 /// If the iterator is dropped before being fully consumed, it drops the remaining elements in arbitrary order.
273 ///
274 /// The returned iterator keeps a mutable borrow on the heap to optimize its implementation.
275 ///
276 /// # Example
277 /// ```
278 /// # use topset::TopSet;
279 /// let mut topset = TopSet::with_init(4, u32::gt, vec![7,5,6,9,4,2,3] );
280 /// let _ = topset.drain();
281 /// assert! (topset.is_empty());
282 /// ```
283 #[inline]
284 pub fn drain(&mut self) -> std::vec::Drain<X> {
285 self.heap.drain(..)
286 }
287
288 /// Resize the top set
289 ///
290 /// If the size decreases, then the lowest items are removed.
291 /// If the size increases, nothing else happens but there is still more room
292 /// for next insertions.
293 ///
294 /// # Example
295 /// ```
296 /// # use topset::TopSet;
297 /// let mut topset = TopSet::with_init(4, u32::gt, vec![7,5,6,9,4,2,3] );
298 ///
299 /// // the topset contains { 7, 5, 6, 9 }
300 /// assert_eq! (topset.peek(), Some(&5));
301 ///
302 /// topset.resize(2);
303 /// // the topset contains { 7, 9 }
304 /// assert_eq! (topset.peek(), Some(&7));
305 ///
306 /// // try to add 1 but no more room left
307 /// assert_eq!( topset.insert(1), Some(1) );
308 ///
309 /// topset.resize(3); // grows by one
310 /// assert_eq!( topset.insert(1), None ); // one room left
311 /// assert_eq!( topset.insert(2), Some(1) ); // but now, is full
312 /// // at this point, the topset contains { 7, 9, 2 }
313 /// ```
314 pub fn resize(&mut self, n: usize)
315 {
316 if self.count < n {
317 self.heap.reserve(n - self.count);
318 } else {
319 while self.heap.len() > n {
320 self.pop();
321 }
322 }
323 self.count = n;
324 }
325
326 /// Pop the lowest item of the top set
327 ///
328 /// Remove and return the _lowest_ item of the top set.
329 /// After this call, there is one more room for a item.
330 ///
331 /// This method is the only way to get the top elements
332 /// in a sorted way (from the lowest to the best).
333 /// Resize the top set
334 ///
335 /// If the size decreases, then the lowest items are removed.
336 /// If the size increases, nothing else happens but there is still more room
337 /// for next insertions.
338 ///
339 /// # Example
340 /// ```
341 /// # use topset::TopSet;
342 /// let mut topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3] );
343 ///
344 /// assert_eq! (topset.pop(), Some(7));
345 /// assert_eq! (topset.pop(), Some(9));
346 /// assert_eq! (topset.pop(), None);
347 /// ```
348 pub fn pop(&mut self) -> Option<X>
349 {
350 match self.heap.len() {
351 0 => None,
352 1|2 => Some(self.heap.swap_remove(0)),
353 _ => {
354 let pop = self.heap.swap_remove(0);
355 self.percolate_down(0);
356 Some(pop)
357 }
358 }
359 }
360
361 /// Removes all the elements in the top set
362 /// # Example
363 /// ```
364 /// # use topset::TopSet;
365 /// let mut topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3] );
366 ///
367 /// assert_eq! (topset.len(), 2);
368 /// topset.clear();
369 /// assert_eq!( topset.len(), 0)
370 /// ```
371 #[inline] pub fn clear(&mut self) { self.heap.clear() }
372
373 /// Checks if an element beats the other.
374 ///
375 /// It does not related to the current elements in the topset but
376 /// refers only to the comparing function (the _beat_).
377 ///
378 /// # Example
379 /// ```
380 /// # use topset::TopSet;
381 /// let mut topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3] );
382 ///
383 /// assert! ( topset.beat(&4, &3));
384 /// assert! ( ! topset.beat(&4, &7));
385 /// ```
386 #[inline] pub fn beat(&self, a:&X, b:&X) -> bool { (self.beat)(a,b) }
387
388 // internal stuff
389 // move i up (to the best)
390 fn percolate_up(&mut self, mut i: usize)
391 {
392 while i > 0 { // so has a parent (not root)
393 let parent = (i-1)/2;
394 // put the greatest the deepest
395 if self.beat(&self.heap[parent], &self.heap[i]) {
396 self.heap.swap(parent, i);
397 i = parent;
398 } else {
399 break;
400 }
401 }
402 }
403
404 // internal stuff
405 // move i as deep as possible
406 fn percolate_down(&mut self, mut i: usize)
407 {
408 loop {
409 let mut child = 2*i+1;
410 if child < self.heap.len()-1 {
411 // to put the greatest the deepest -> select the greatest child
412 if self.beat(&self.heap[child], &self.heap[child+1]) {
413 child += 1;
414 }
415 // put the greatest the deepest
416 if self.beat(&self.heap[i], &self.heap[child]) {
417 self.heap.swap(i, child);
418 i = child;
419 } else {
420 break;
421 }
422 } else {
423 if (child == self.heap.len() - 1) && self.beat(&self.heap[i], &self.heap[child]) {
424 // only one child
425 self.heap.swap(i, child);
426 }
427 // end of heap
428 break;
429 }
430 }
431 }
432}
433
434
435impl<X,C> IntoIterator for TopSet<X,C>
436 where C: Fn(&X,&X) -> bool
437{
438 type Item = X;
439 type IntoIter = <Vec<X> as IntoIterator>::IntoIter;
440
441 #[inline]
442 fn into_iter(self) -> Self::IntoIter {
443 self.heap.into_iter()
444 }
445}
446
447impl<'a,X,C> IntoIterator for &'a TopSet<X,C>
448 where C: Fn(&X,&X) -> bool
449{
450 type Item = &'a X;
451 type IntoIter = <&'a Vec<X> as IntoIterator>::IntoIter;
452
453 #[inline]
454 fn into_iter(self) -> Self::IntoIter {
455 self.heap.iter()
456 }
457}
458
459impl<X,C> Extend<X> for TopSet<X,C>
460 where C: Fn(&X,&X) -> bool
461{
462 #[inline]
463 fn extend<T: IntoIterator<Item=X>>(&mut self, iter: T) {
464 iter.into_iter().for_each(|x| { self.insert(x); } )
465 }
466}
467
468
469impl<X,C> Debug for TopSet<X,C>
470 where X:Debug, C: Fn(&X,&X) -> bool
471{
472 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
473 self.heap.fmt(f)
474 }
475}
476
477
478
479#[cfg(test)]
480mod tests {
481 use crate::iter::TopSetReducing;
482 use crate::TopSet;
483
484 #[test]
485 fn lowest_cost()
486 {
487 let mut top = TopSet::<f32,_>::new(5, f32::lt);
488 top.extend(vec![81.5, 4.5, 4., 1., 45., 22., 11.]);
489 top.extend(vec![81.5, 4.5, 4., 1., 45., 22., 11.]);
490
491 assert_eq![ top.pop(), Some(4.5) ];
492 assert_eq![ top.pop(), Some(4.) ];
493 assert_eq![ top.pop(), Some(4.) ];
494 assert_eq![ top.pop(), Some(1.) ];
495 assert_eq![ top.pop(), Some(1.) ];
496 assert_eq![ top.pop(), None ];
497 }
498
499 #[test]
500 fn greatest_score()
501 {
502 assert_eq![
503 vec![81,5, 4,5,4,1,45,22,1,5,97,5,877,12,0]
504 .topset(5, u32::gt)
505 .into_iter()
506 .last(),
507 Some(877)];
508 }
509}