Skip to content

Commit 6d4e429

Browse files
committed
Impl dedup
1 parent c0941df commit 6d4e429

File tree

4 files changed

+272
-1
lines changed

4 files changed

+272
-1
lines changed
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
use crate::mem::swap;
2+
3+
/// An iterator that removes all but the first of consecutive elements in a
4+
/// given iterator according to the [`PartialEq`] trait implementation.
5+
///
6+
/// This `struct` is created by the [`dedup`] method on [`Iterator`]. See its
7+
/// documentation for more.
8+
///
9+
/// [`dedup`]: Iterator::dedup
10+
/// [`Iterator`]: trait.Iterator.html
11+
#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")]
12+
#[derive(Debug, Clone, Copy)]
13+
pub struct Dedup<I, T> {
14+
inner: I,
15+
last: Option<T>,
16+
}
17+
18+
impl<I, T> Dedup<I, T> {
19+
pub(crate) const fn new(inner: I) -> Self {
20+
Self { inner, last: None }
21+
}
22+
}
23+
24+
#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")]
25+
impl<I, T> Iterator for Dedup<I, T>
26+
where
27+
I: Iterator<Item = T>,
28+
T: PartialEq,
29+
{
30+
type Item = T;
31+
32+
fn next(&mut self) -> Option<Self::Item> {
33+
if self.last.is_none() {
34+
self.last = self.inner.next();
35+
}
36+
37+
let last_item = self.last.as_ref()?;
38+
let mut next = loop {
39+
let curr = self.inner.next();
40+
if let Some(curr_item) = &curr {
41+
if last_item != curr_item {
42+
break curr;
43+
}
44+
} else {
45+
break None;
46+
}
47+
};
48+
49+
swap(&mut self.last, &mut next);
50+
next
51+
}
52+
53+
fn size_hint(&self) -> (usize, Option<usize>) {
54+
(0, self.inner.size_hint().1)
55+
}
56+
}
57+
58+
/// An iterator that removes all but the first of consecutive elements in a
59+
/// given iterator satisfying a given equality relation.
60+
///
61+
/// This `struct` is created by the [`dedup_by`] method on [`Iterator`].
62+
/// See its documentation for more.
63+
///
64+
/// [`dedup_by`]: Iterator::dedup_by
65+
/// [`Iterator`]: trait.Iterator.html
66+
#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")]
67+
#[derive(Debug, Clone, Copy)]
68+
pub struct DedupBy<I, F, T> {
69+
inner: I,
70+
same_bucket: F,
71+
last: Option<T>,
72+
}
73+
74+
impl<I, F, T> DedupBy<I, F, T> {
75+
pub(crate) const fn new(inner: I, same_bucket: F) -> Self {
76+
Self {
77+
inner,
78+
same_bucket,
79+
last: None,
80+
}
81+
}
82+
}
83+
84+
#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")]
85+
impl<I, F, T> Iterator for DedupBy<I, F, T>
86+
where
87+
I: Iterator<Item = T>,
88+
F: FnMut(&T, &T) -> bool,
89+
{
90+
type Item = T;
91+
92+
fn next(&mut self) -> Option<Self::Item> {
93+
if self.last.is_none() {
94+
self.last = self.inner.next();
95+
}
96+
97+
let last_item = self.last.as_ref()?;
98+
let mut next = loop {
99+
let curr = self.inner.next();
100+
if let Some(curr_item) = &curr {
101+
if !(self.same_bucket)(last_item, curr_item) {
102+
break curr;
103+
}
104+
} else {
105+
break None;
106+
}
107+
};
108+
109+
swap(&mut self.last, &mut next);
110+
next
111+
}
112+
113+
fn size_hint(&self) -> (usize, Option<usize>) {
114+
(0, self.inner.size_hint().1)
115+
}
116+
}
117+
118+
/// An iterator that removes all but the first of consecutive elements in a
119+
/// given iterator that resolve to the same key.
120+
///
121+
/// This `struct` is created by the [`dedup_by_key`] method on [`Iterator`].
122+
/// See its documentation for more.
123+
///
124+
/// [`dedup_by_key`]: Iterator::dedup_by_key
125+
/// [`Iterator`]: trait.Iterator.html
126+
#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")]
127+
#[derive(Debug, Clone, Copy)]
128+
pub struct DedupByKey<I, F, T> {
129+
inner: I,
130+
key: F,
131+
last: Option<T>,
132+
}
133+
134+
impl<I, F, T> DedupByKey<I, F, T> {
135+
pub(crate) const fn new(inner: I, key: F) -> Self {
136+
Self {
137+
inner,
138+
key,
139+
last: None,
140+
}
141+
}
142+
}
143+
144+
#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")]
145+
impl<I, F, K, T> Iterator for DedupByKey<I, F, T>
146+
where
147+
I: Iterator<Item = T>,
148+
F: Fn(&T) -> K,
149+
K: PartialEq,
150+
{
151+
type Item = T;
152+
153+
fn next(&mut self) -> Option<Self::Item> {
154+
if self.last.is_none() {
155+
self.last = self.inner.next();
156+
}
157+
158+
let last_item = self.last.as_ref()?;
159+
let mut next = loop {
160+
let curr = self.inner.next();
161+
if let Some(curr_item) = &curr {
162+
if (self.key)(last_item) != (self.key)(curr_item) {
163+
break curr;
164+
}
165+
} else {
166+
break None;
167+
}
168+
};
169+
170+
swap(&mut self.last, &mut next);
171+
next
172+
}
173+
174+
fn size_hint(&self) -> (usize, Option<usize>) {
175+
(0, self.inner.size_hint().1)
176+
}
177+
}

library/core/src/iter/adapters/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ mod chain;
77
mod cloned;
88
mod copied;
99
mod cycle;
10+
mod dedup;
1011
mod enumerate;
1112
mod filter;
1213
mod filter_map;
@@ -66,7 +67,10 @@ pub use self::zip::TrustedRandomAccessNoCoerce;
6667
#[stable(feature = "iter_zip", since = "1.59.0")]
6768
pub use self::zip::zip;
6869

69-
/// This trait provides transitive access to source-stage in an iterator-adapter pipeline
70+
#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")]
71+
pub use self::dedup::{Dedup, DedupBy, DedupByKey};
72+
73+
/// This trait provides transitive access to source-stage in an interator-adapter pipeline
7074
/// under the conditions that
7175
/// * the iterator source `S` itself implements `SourceIter<Source = S>`
7276
/// * there is a delegating implementation of this trait for each adapter in the pipeline between

library/core/src/iter/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,8 @@ pub use self::adapters::{
425425
};
426426
#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
427427
pub use self::adapters::{Intersperse, IntersperseWith};
428+
#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")]
429+
pub use self::adapters::{Dedup, DedupBy, DedupByKey};
428430

429431
pub(crate) use self::adapters::try_process;
430432

library/core/src/iter/traits/iterator.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use super::super::try_process;
66
use super::super::ByRefSized;
77
use super::super::TrustedRandomAccessNoCoerce;
88
use super::super::{ArrayChunks, Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
9+
use super::super::{Dedup, DedupBy, DedupByKey};
910
use super::super::{FlatMap, Flatten};
1011
use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip};
1112
use super::super::{
@@ -1689,6 +1690,93 @@ pub trait Iterator {
16891690
Inspect::new(self, f)
16901691
}
16911692

1693+
/// Removes all but the first of consecutive elements in the iterator according to the
1694+
/// [`PartialEq`] trait implementation.
1695+
///
1696+
/// If the iterator is sorted, this removes all duplicates.
1697+
///
1698+
/// # Examples
1699+
///
1700+
/// ```
1701+
/// let vec = vec![1, 2, 2, 3, 2];
1702+
///
1703+
/// let mut iter = vec.into_iter().dedup();
1704+
///
1705+
/// assert_eq!(iter.next(), Some(1));
1706+
/// assert_eq!(iter.next(), Some(2));
1707+
/// assert_eq!(iter.next(), Some(3));
1708+
/// assert_eq!(iter.next(), Some(2));
1709+
/// assert_eq!(iter.next(), None);
1710+
/// ```
1711+
#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")]
1712+
#[inline]
1713+
fn dedup(self) -> Dedup<Self, Self::Item>
1714+
where
1715+
Self: Sized
1716+
{
1717+
Dedup::new(self)
1718+
}
1719+
1720+
/// Removes all but the first of consecutive elements in the iterator satisfying a given equality
1721+
/// relation.
1722+
///
1723+
/// The `same_bucket` function is passed a references to two elements from the iterator and
1724+
/// must determine if the elements compare equal.
1725+
///
1726+
/// If the iterator is sorted, this removes all duplicates.
1727+
///
1728+
/// # Examples
1729+
///
1730+
/// ```
1731+
/// let vec = vec!["foo", "bar", "Bar", "baz", "bar"];
1732+
///
1733+
/// let mut iter = vec.into_iter().dedup_by(|a, b| a.eq_ignore_ascii_case(b));
1734+
///
1735+
/// assert_eq!(iter.next(), Some("foo"));
1736+
/// assert_eq!(iter.next(), Some("bar"));
1737+
/// assert_eq!(iter.next(), Some("baz"));
1738+
/// assert_eq!(iter.next(), Some("bar"));
1739+
/// assert_eq!(iter.next(), None);
1740+
/// ```
1741+
#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")]
1742+
#[inline]
1743+
fn dedup_by<F>(self, same_bucket: F) -> DedupBy<Self, F, Self::Item>
1744+
where
1745+
Self: Sized,
1746+
F: Fn(&Self::Item, &Self::Item) -> bool,
1747+
{
1748+
DedupBy::new(self, same_bucket)
1749+
}
1750+
1751+
/// Removes all but the first of consecutive elements in the iterator that
1752+
/// resolve to the same key.
1753+
///
1754+
/// If the iterator is sorted, this removes all duplicates.
1755+
///
1756+
/// # Examples
1757+
///
1758+
/// ```
1759+
/// let vec = vec![10, 20, 21, 30, 20];
1760+
///
1761+
/// let mut iter = vec.into_iter().dedup_by_key(|&i| i / 10);
1762+
///
1763+
/// assert_eq!(iter.next(), Some(10));
1764+
/// assert_eq!(iter.next(), Some(20));
1765+
/// assert_eq!(iter.next(), Some(30));
1766+
/// assert_eq!(iter.next(), Some(20));
1767+
/// assert_eq!(iter.next(), None);
1768+
/// ```
1769+
#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")]
1770+
#[inline]
1771+
fn dedup_by_key<F, K>(self, key: F) -> DedupByKey<Self, F, Self::Item>
1772+
where
1773+
Self: Sized,
1774+
F: Fn(&Self::Item) -> K,
1775+
K: PartialEq,
1776+
{
1777+
DedupByKey::new(self, key)
1778+
}
1779+
16921780
/// Borrows an iterator, rather than consuming it.
16931781
///
16941782
/// This is useful to allow applying iterator adapters while still

0 commit comments

Comments
 (0)