-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Add dedup
, dedup_by
and dedup_by_key
to the Iterator
trait
#83748
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
Changes from all commits
6d4e429
bf425a0
d59eb00
5e24347
ca137db
1ec9aa8
cc480ba
7d9b058
87d7f9a
2e1beb1
d0f9feb
d1e6d27
1a04987
69b18f7
d8aebea
5dec9ce
6cd757a
fcbff04
9a906dd
3fbbfdb
9648fb5
67d01d5
a822aad
f57678c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
#![unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] | ||
|
||
/// An iterator that removes all but the first of consecutive elements in a | ||
/// given iterator according to the [`PartialEq`] trait implementation. | ||
/// | ||
/// This `struct` is created by [`Iterator::dedup`]. | ||
/// See its documentation for more. | ||
/// | ||
/// [`Iterator::dedup`]: Iterator::dedup | ||
#[derive(Debug, Clone)] | ||
pub struct Dedup<I> | ||
where | ||
I: Iterator, | ||
{ | ||
inner: I, | ||
last: Option<Option<I::Item>>, | ||
} | ||
|
||
impl<I> Dedup<I> | ||
where | ||
I: Iterator, | ||
{ | ||
#[inline] | ||
pub(crate) fn new(inner: I) -> Self { | ||
Self { inner, last: None } | ||
} | ||
} | ||
|
||
impl<I> Iterator for Dedup<I> | ||
where | ||
I: Iterator, | ||
I::Item: PartialEq, | ||
{ | ||
type Item = I::Item; | ||
|
||
#[inline] | ||
fn next(&mut self) -> Option<Self::Item> { | ||
let Self { inner, last } = self; | ||
let last = last.get_or_insert_with(|| inner.next()); | ||
let last_item = last.as_ref()?; | ||
let next = inner.find(|next_item| next_item != last_item); | ||
crate::mem::replace(last, next) | ||
} | ||
|
||
#[inline] | ||
fn size_hint(&self) -> (usize, Option<usize>) { | ||
let min = matches!(self.last, Some(Some(_))).into(); | ||
let max = self.inner.size_hint().1.map(|max| max + min); | ||
(min, max) | ||
} | ||
} | ||
|
||
/// An iterator that removes all but the first of consecutive elements in a | ||
/// given iterator satisfying a given equality relation. | ||
/// | ||
/// This `struct` is created by [`Iterator::dedup_by`]. | ||
/// See its documentation for more. | ||
/// | ||
/// [`Iterator::dedup_by`]: Iterator::dedup_by | ||
#[derive(Debug, Clone)] | ||
pub struct DedupBy<I, F> | ||
where | ||
I: Iterator, | ||
{ | ||
inner: I, | ||
same_bucket: F, | ||
last: Option<Option<I::Item>>, | ||
} | ||
|
||
impl<I, F> DedupBy<I, F> | ||
where | ||
I: Iterator, | ||
{ | ||
#[inline] | ||
pub(crate) fn new(inner: I, same_bucket: F) -> Self { | ||
Self { inner, same_bucket, last: None } | ||
} | ||
} | ||
|
||
impl<I, F> Iterator for DedupBy<I, F> | ||
where | ||
I: Iterator, | ||
F: FnMut(&I::Item, &I::Item) -> bool, | ||
{ | ||
type Item = I::Item; | ||
|
||
#[inline] | ||
fn next(&mut self) -> Option<Self::Item> { | ||
let Self { inner, last, same_bucket } = self; | ||
let last = last.get_or_insert_with(|| inner.next()); | ||
let last_item = last.as_ref()?; | ||
let next = inner.find(|next_item| !(same_bucket)(next_item, last_item)); | ||
crate::mem::replace(last, next) | ||
} | ||
|
||
#[inline] | ||
fn size_hint(&self) -> (usize, Option<usize>) { | ||
let min = matches!(self.last, Some(Some(_))).into(); | ||
let max = self.inner.size_hint().1.map(|max| max + min); | ||
(min, max) | ||
} | ||
} | ||
|
||
/// An iterator that removes all but the first of consecutive elements in a | ||
/// given iterator that resolve to the same key. | ||
/// | ||
/// This `struct` is created by [`Iterator::dedup_by_key`]. | ||
/// See its documentation for more. | ||
/// | ||
/// [`Iterator::dedup_by_key`]: Iterator::dedup_by_key | ||
#[derive(Debug, Clone)] | ||
pub struct DedupByKey<I, F, K> | ||
where | ||
I: Iterator, | ||
F: FnMut(&I::Item) -> K, | ||
{ | ||
inner: I, | ||
key: F, | ||
last: Option<Option<I::Item>>, | ||
} | ||
|
||
impl<I, F, K> DedupByKey<I, F, K> | ||
where | ||
I: Iterator, | ||
F: FnMut(&I::Item) -> K, | ||
{ | ||
#[inline] | ||
pub(crate) fn new(inner: I, key: F) -> Self { | ||
Self { inner, key, last: None } | ||
} | ||
} | ||
|
||
impl<I, F, K> Iterator for DedupByKey<I, F, K> | ||
where | ||
I: Iterator, | ||
F: FnMut(&I::Item) -> K, | ||
K: PartialEq, | ||
{ | ||
type Item = I::Item; | ||
|
||
#[inline] | ||
fn next(&mut self) -> Option<Self::Item> { | ||
let Self { inner, last, key } = self; | ||
let last = last.get_or_insert_with(|| inner.next()); | ||
let last_item = last.as_ref()?; | ||
let next = inner.find(|next_item| key(next_item) != key(last_item)); | ||
crate::mem::replace(last, next) | ||
} | ||
slerpyyy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
#[inline] | ||
fn size_hint(&self) -> (usize, Option<usize>) { | ||
let min = matches!(self.last, Some(Some(_))).into(); | ||
let max = self.inner.size_hint().1.map(|max| max + min); | ||
(min, max) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -6,6 +6,7 @@ use super::super::try_process; | |||||
use super::super::ByRefSized; | ||||||
use super::super::TrustedRandomAccessNoCoerce; | ||||||
use super::super::{ArrayChunks, Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; | ||||||
use super::super::{Dedup, DedupBy, DedupByKey}; | ||||||
use super::super::{FlatMap, Flatten}; | ||||||
use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip}; | ||||||
use super::super::{ | ||||||
|
@@ -1689,6 +1690,142 @@ pub trait Iterator { | |||||
Inspect::new(self, f) | ||||||
} | ||||||
|
||||||
/// Removes all but the first of consecutive repeated elements in the iterator | ||||||
/// according to the [`PartialEq`] trait implementation. | ||||||
/// | ||||||
/// For an iterator yielding infinitely many consecutive duplicates, | ||||||
/// this may result in an infinite loop. | ||||||
/// | ||||||
/// If the iterator is sorted, this removes all duplicates. | ||||||
/// | ||||||
/// # Examples | ||||||
/// | ||||||
/// Basic usage: | ||||||
/// | ||||||
/// ``` | ||||||
/// #![feature(iter_dedup)] | ||||||
/// | ||||||
/// let vec = vec![1, 2, 2, 3, 2]; | ||||||
/// | ||||||
/// let mut iter = vec.into_iter().dedup(); | ||||||
/// | ||||||
/// assert_eq!(iter.next(), Some(1)); | ||||||
/// assert_eq!(iter.next(), Some(2)); | ||||||
/// assert_eq!(iter.next(), Some(3)); | ||||||
/// assert_eq!(iter.next(), Some(2)); | ||||||
/// assert_eq!(iter.next(), None); | ||||||
/// ``` | ||||||
/// | ||||||
/// Example of an infinite loop: | ||||||
/// | ||||||
/// ```no_run | ||||||
/// #![feature(iter_dedup)] | ||||||
/// | ||||||
/// // this will never terminate | ||||||
/// let _ = std::iter::repeat(2).dedup().next(); | ||||||
/// ``` | ||||||
#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] | ||||||
#[inline] | ||||||
fn dedup(self) -> Dedup<Self> | ||||||
where | ||||||
Self: Sized, | ||||||
Self::Item: PartialEq, | ||||||
{ | ||||||
Dedup::new(self) | ||||||
} | ||||||
|
||||||
/// Removes all but the first of consecutive elements in the iterator | ||||||
/// satisfying a given equality relation. | ||||||
/// | ||||||
/// The `same_bucket` function is passed a references to two elements from | ||||||
/// the iterator and must determine if the elements compare equal. | ||||||
/// | ||||||
/// For an iterator yielding infinitely many consecutive duplicates, | ||||||
/// this may result in an infinite loop. | ||||||
/// | ||||||
/// If the iterator is sorted, this removes all duplicates. | ||||||
/// | ||||||
/// # Examples | ||||||
/// | ||||||
/// Basic usage: | ||||||
/// | ||||||
/// ``` | ||||||
/// #![feature(iter_dedup)] | ||||||
/// | ||||||
/// let vec = vec!["foo", "bar", "Bar", "baz", "bar"]; | ||||||
/// | ||||||
/// let mut iter = vec.into_iter().dedup_by(|a, b| a.eq_ignore_ascii_case(b)); | ||||||
/// | ||||||
/// assert_eq!(iter.next(), Some("foo")); | ||||||
/// assert_eq!(iter.next(), Some("bar")); | ||||||
/// assert_eq!(iter.next(), Some("baz")); | ||||||
/// assert_eq!(iter.next(), Some("bar")); | ||||||
/// assert_eq!(iter.next(), None); | ||||||
/// ``` | ||||||
/// | ||||||
/// Example of an infinite loop: | ||||||
/// | ||||||
/// ```no_run | ||||||
/// #![feature(iter_dedup)] | ||||||
/// | ||||||
/// // this will never terminate | ||||||
/// let _ = std::iter::repeat(2).dedup_by(|a, b| a == b).next(); | ||||||
/// ``` | ||||||
#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] | ||||||
#[inline] | ||||||
fn dedup_by<F>(self, same_bucket: F) -> DedupBy<Self, F> | ||||||
where | ||||||
Self: Sized, | ||||||
F: FnMut(&Self::Item, &Self::Item) -> bool, | ||||||
{ | ||||||
DedupBy::new(self, same_bucket) | ||||||
} | ||||||
|
||||||
/// Removes all but the first of consecutive elements in the iterator | ||||||
/// that resolve to the same key. | ||||||
/// | ||||||
/// For an iterator yielding infinitely many consecutive duplicates, | ||||||
/// this may result in an infinite loop. | ||||||
/// | ||||||
/// If the iterator is sorted, this removes all duplicates. | ||||||
/// | ||||||
/// # Examples | ||||||
/// | ||||||
/// Basic usage: | ||||||
/// | ||||||
/// ``` | ||||||
/// #![feature(iter_dedup)] | ||||||
/// | ||||||
/// let vec = vec![10, 20, 21, 30, 20]; | ||||||
/// | ||||||
/// let mut iter = vec.into_iter().dedup_by_key(|&i| i / 10); | ||||||
/// | ||||||
/// assert_eq!(iter.next(), Some(10)); | ||||||
/// assert_eq!(iter.next(), Some(20)); | ||||||
/// assert_eq!(iter.next(), Some(30)); | ||||||
/// assert_eq!(iter.next(), Some(20)); | ||||||
/// assert_eq!(iter.next(), None); | ||||||
/// ``` | ||||||
/// | ||||||
/// Example of an infinite loop: | ||||||
/// | ||||||
/// ```no_run | ||||||
/// #![feature(iter_dedup)] | ||||||
/// | ||||||
/// // this will never terminate | ||||||
/// let _ = std::iter::repeat(2).dedup_by_key(|&n| n).next(); | ||||||
/// ``` | ||||||
#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] | ||||||
#[inline] | ||||||
fn dedup_by_key<F, K>(self, key: F) -> DedupByKey<Self, F, K> | ||||||
where | ||||||
Self: Sized, | ||||||
F: FnMut(&Self::Item) -> K, | ||||||
K: PartialEq, | ||||||
{ | ||||||
DedupByKey::new(self, key) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
https://doc.rust-lang.org/stable/src/alloc/vec/mod.rs.html#1441 self.dedup_by(|a, b| key(a) == key(b)) Not sure if this will work though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After that change, what is the signature of the function There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can use the C++ way to give your closure type a name: struct EqByKey<F> {
f: F
}
impl<I, K: PartialEq, F: FnMut(&I) -> K> FnOnce<(&I, &I)> for EqByKey<F> {
type Output = bool;
extern "rust-call" fn call_once(mut self, (a, b): (&I, &I)) -> bool {
(self.f)(a) == (self.f)(b)
}
}
impl<I, K: PartialEq, F: FnMut(&I) -> K> FnMut<(&I, &I)> for EqByKey<F> {
extern "rust-call" fn call_mut(&mut self, (a, b): (&I, &I)) -> bool {
(self.f)(a) == (self.f)(b)
}
} Edit: just saw #83748 (comment) |
||||||
} | ||||||
|
||||||
/// Borrows an iterator, rather than consuming it. | ||||||
/// | ||||||
/// This is useful to allow applying iterator adapters while still | ||||||
|
Uh oh!
There was an error while loading. Please reload this page.