Skip to content

Commit 281a2ba

Browse files
improve Vec::dedup_by documentation
Co-authored-by: Mark Rousskov <mark.simulacrum@gmail.com>
1 parent 89a9993 commit 281a2ba

2 files changed

Lines changed: 47 additions & 17 deletions

File tree

library/alloc/src/vec/mod.rs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2626,23 +2626,49 @@ impl<T, A: Allocator> Vec<T, A> {
26262626
self.dedup_by(|a, b| key(a) == key(b))
26272627
}
26282628

2629-
/// Removes all but the first of consecutive elements in the vector satisfying a given equality
2630-
/// relation.
2629+
/// Removes all but the first of consecutive elements in the vector that are
2630+
/// "equal" according to the given predicate function.
26312631
///
2632-
/// The `same_bucket` function is passed references to two elements from the vector and
2633-
/// must determine if the elements compare equal. The elements are passed in opposite order
2634-
/// from their order in the slice, so if `same_bucket(a, b)` returns `true`, `a` is removed.
2632+
/// The predicate `same_bucket(x, p)` is passed references to two elements.
2633+
/// If it returns `true`, the element `x` is removed from the vector.
26352634
///
2636-
/// If the vector is sorted, this removes all duplicates.
2635+
/// The element `p` occurs *before* `x` in the vector (`[.., p, .., x, ..]`),
2636+
/// so `same_bucket(x, p)` is receiving them in reversed order (unlike [`windows`]).
2637+
///
2638+
/// If the vector is sorted, this removes all duplicates. For more complicated predicates
2639+
/// however, the order (ascending vs. descending) can matter.
2640+
///
2641+
/// [`windows`]: slice::windows
26372642
///
26382643
/// # Examples
26392644
///
26402645
/// ```
26412646
/// let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"];
2647+
/// vec.dedup_by(|x, p| x.eq_ignore_ascii_case(p));
2648+
/// assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
2649+
/// ```
26422650
///
2643-
/// vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
2651+
/// Both references passed to `same_bucket` are mutable.
2652+
/// This allows merging elements by mutating `p` and returning `true`:
26442653
///
2645-
/// assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
2654+
/// ```
2655+
/// let mut ranges = vec![1..2, 2..4, 2..5, 8..9];
2656+
///
2657+
/// // Sort ranges by start, and if equal, by end (lexicographically)
2658+
/// // Sorting in reverse instead (`x.start.cmp(&p.start)...`) would later fail
2659+
/// ranges.sort_unstable_by(|p, x| p.start.cmp(&x.start).then(p.end.cmp(&x.end)));
2660+
///
2661+
/// // Merge touching (`1..2` and `2..4`) and then overlapping (`1..4` and `2..5`) ranges
2662+
/// ranges.dedup_by(|x, p| {
2663+
/// if p.end >= x.start {
2664+
/// p.end = p.end.max(x.end);
2665+
/// true
2666+
/// } else {
2667+
/// false
2668+
/// }
2669+
/// });
2670+
///
2671+
/// assert_eq!(ranges, [1..5, 8..9]);
26462672
/// ```
26472673
#[stable(feature = "dedup_by", since = "1.16.0")]
26482674
pub fn dedup_by<F>(&mut self, mut same_bucket: F)

library/core/src/slice/mod.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3689,18 +3689,22 @@ impl<T> [T] {
36893689
self.partition_dedup_by(|a, b| a == b)
36903690
}
36913691

3692-
/// Moves all but the first of consecutive elements to the end of the slice satisfying
3693-
/// a given equality relation.
3692+
/// Moves all but the first of consecutive elements to the end of the slice that are
3693+
/// "equal" according to the given predicate function.
36943694
///
36953695
/// Returns two slices. The first contains no consecutive repeated elements.
36963696
/// The second contains all the duplicates in no specified order.
36973697
///
3698-
/// The `same_bucket` function is passed references to two elements from the slice and
3699-
/// must determine if the elements compare equal. The elements are passed in opposite order
3700-
/// from their order in the slice, so if `same_bucket(a, b)` returns `true`, `a` is moved
3701-
/// at the end of the slice.
3698+
/// The predicate `same_bucket(p, x)` is passed references to two elements from
3699+
/// the slice and must determine if the elements compare equal. The element `p` occurs
3700+
/// *before* `x` in the slice (`[.., p, .., x, ..]`), so `same_bucket(x, p)`
3701+
/// is receiving them in reversed order.
37023702
///
3703-
/// If the slice is sorted, the first returned slice contains no duplicates.
3703+
/// If the slice is sorted, the first returned slice contains no duplicates. For more
3704+
/// complicated predicates however, the order (ascending vs. descending) can matter.
3705+
///
3706+
/// Both references passed to `same_bucket` are mutable.
3707+
/// This allows merged elements in the first slice by mutating `p` and returning `true`.
37043708
///
37053709
/// # Examples
37063710
///
@@ -3709,7 +3713,7 @@ impl<T> [T] {
37093713
///
37103714
/// let mut slice = ["foo", "Foo", "BAZ", "Bar", "bar", "baz", "BAZ"];
37113715
///
3712-
/// let (dedup, duplicates) = slice.partition_dedup_by(|a, b| a.eq_ignore_ascii_case(b));
3716+
/// let (dedup, duplicates) = slice.partition_dedup_by(|x, p| x.eq_ignore_ascii_case(p));
37133717
///
37143718
/// assert_eq!(dedup, ["foo", "BAZ", "Bar", "baz"]);
37153719
/// assert_eq!(duplicates, ["bar", "Foo", "BAZ"]);
@@ -3790,7 +3794,7 @@ impl<T> [T] {
37903794
// are less than `len`, thus are inside `self`. `prev_ptr_write` points to
37913795
// one element before `ptr_write`, but `next_write` starts at 1, so
37923796
// `prev_ptr_write` is never less than 0 and is inside the slice.
3793-
// This fulfils the requirements for dereferencing `ptr_read`, `prev_ptr_write`
3797+
// This fulfills the requirements for dereferencing `ptr_read`, `prev_ptr_write`
37943798
// and `ptr_write`, and for using `ptr.add(next_read)`, `ptr.add(next_write - 1)`
37953799
// and `prev_ptr_write.offset(1)`.
37963800
//

0 commit comments

Comments
 (0)