Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 34 additions & 8 deletions library/alloc/src/vec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2626,23 +2626,49 @@ impl<T, A: Allocator> Vec<T, A> {
self.dedup_by(|a, b| key(a) == key(b))
}

/// Removes all but the first of consecutive elements in the vector satisfying a given equality
/// relation.
/// Removes all but the first of consecutive elements in the vector that are
/// "equal" according to the given predicate function.
///
/// The `same_bucket` function is passed references to two elements from the vector and
/// must determine if the elements compare equal. The elements are passed in opposite order
/// from their order in the slice, so if `same_bucket(a, b)` returns `true`, `a` is removed.
/// The predicate `same_bucket(x, p)` is passed references to two elements.
/// If it returns `true`, the element `x` is removed from the vector.
///
/// If the vector is sorted, this removes all duplicates.
/// The element `p` occurs *before* `x` in the vector (`[.., p, .., x, ..]`),
/// so `same_bucket(x, p)` is receiving them in reversed order (unlike [`windows`]).
///
/// If the vector is sorted, this removes all duplicates. For more complicated predicates
/// however, the order (ascending vs. descending) can matter.
///
/// [`windows`]: slice::windows
///
/// # Examples
///
/// ```
/// let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"];
/// vec.dedup_by(|x, p| x.eq_ignore_ascii_case(p));
/// assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
/// ```
///
/// vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
/// Both references passed to `same_bucket` are mutable.
/// This allows merging elements by mutating `p` and returning `true`:
///
/// assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
/// ```
/// let mut ranges = vec![1..2, 2..4, 2..5, 8..9];
///
/// // Sort ranges by start, and if equal, by end (lexicographically)
/// // Sorting in reverse instead (`x.start.cmp(&p.start)...`) would later fail
/// ranges.sort_unstable_by(|p, x| p.start.cmp(&x.start).then(p.end.cmp(&x.end)));
///
/// // Merge touching (`1..2` and `2..4`) and then overlapping (`1..4` and `2..5`) ranges
/// ranges.dedup_by(|x, p| {
/// if p.end >= x.start {
/// p.end = p.end.max(x.end);
/// true
/// } else {
/// false
/// }
/// });
///
/// assert_eq!(ranges, [1..5, 8..9]);
/// ```
#[stable(feature = "dedup_by", since = "1.16.0")]
pub fn dedup_by<F>(&mut self, mut same_bucket: F)
Expand Down
22 changes: 13 additions & 9 deletions library/core/src/slice/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3689,18 +3689,22 @@ impl<T> [T] {
self.partition_dedup_by(|a, b| a == b)
}

/// Moves all but the first of consecutive elements to the end of the slice satisfying
/// a given equality relation.
/// Moves all but the first of consecutive elements to the end of the slice that are
/// "equal" according to the given predicate function.
///
/// Returns two slices. The first contains no consecutive repeated elements.
/// The second contains all the duplicates in no specified order.
///
/// The `same_bucket` function is passed references to two elements from the slice and
/// must determine if the elements compare equal. The elements are passed in opposite order
/// from their order in the slice, so if `same_bucket(a, b)` returns `true`, `a` is moved
/// at the end of the slice.
/// The predicate `same_bucket(x, p)` is passed references to two elements from
/// the slice and must determine if the elements compare equal. The element `p` occurs
/// *before* `x` in the slice (`[.., p, .., x, ..]`), so `same_bucket(x, p)`
/// is receiving them in reversed order.
///
/// If the slice is sorted, the first returned slice contains no duplicates.
/// If the slice is sorted, the first returned slice contains no duplicates. For more
/// complicated predicates however, the order (ascending vs. descending) can matter.
///
/// Both references passed to `same_bucket` are mutable.
/// This allows merged elements in the first slice by mutating `p` and returning `true`.
///
/// # Examples
///
Expand All @@ -3709,7 +3713,7 @@ impl<T> [T] {
///
/// let mut slice = ["foo", "Foo", "BAZ", "Bar", "bar", "baz", "BAZ"];
///
/// let (dedup, duplicates) = slice.partition_dedup_by(|a, b| a.eq_ignore_ascii_case(b));
/// let (dedup, duplicates) = slice.partition_dedup_by(|x, p| x.eq_ignore_ascii_case(p));
///
/// assert_eq!(dedup, ["foo", "BAZ", "Bar", "baz"]);
/// assert_eq!(duplicates, ["bar", "Foo", "BAZ"]);
Expand Down Expand Up @@ -3790,7 +3794,7 @@ impl<T> [T] {
// are less than `len`, thus are inside `self`. `prev_ptr_write` points to
// one element before `ptr_write`, but `next_write` starts at 1, so
// `prev_ptr_write` is never less than 0 and is inside the slice.
// This fulfils the requirements for dereferencing `ptr_read`, `prev_ptr_write`
// This fulfills the requirements for dereferencing `ptr_read`, `prev_ptr_write`
// and `ptr_write`, and for using `ptr.add(next_read)`, `ptr.add(next_write - 1)`
// and `prev_ptr_write.offset(1)`.
//
Expand Down
Loading