Skip to content

Commit 1b0c56c

Browse files
committed
add Iterator::dedup and friends
1 parent 6ba0ce4 commit 1b0c56c

File tree

4 files changed

+214
-0
lines changed

4 files changed

+214
-0
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
trait DedupPredicate<T> {
2+
fn eq(&mut self, a: &T, b: &T) -> bool;
3+
}
4+
5+
impl<T, F: FnMut(&T, &T) -> bool> DedupPredicate<T> for F {
6+
fn eq(&mut self, a: &T, b: &T) -> bool {
7+
self(a, b)
8+
}
9+
}
10+
11+
#[unstable(feature = "iter_dedup", issue = "83747")]
12+
#[doc(hidden)]
13+
#[derive(Debug)]
14+
pub struct DedupEq;
15+
16+
impl<T: PartialEq> DedupPredicate<T> for DedupEq {
17+
fn eq(&mut self, a: &T, b: &T) -> bool {
18+
a == b
19+
}
20+
}
21+
22+
#[unstable(feature = "iter_dedup", issue = "83747")]
23+
#[doc(hidden)]
24+
#[derive(Debug)]
25+
pub struct DedupKey<F>(pub F);
26+
27+
impl<T, K: PartialEq, F: Fn(&T) -> K> DedupPredicate<T> for DedupKey<F> {
28+
fn eq(&mut self, a: &T, b: &T) -> bool {
29+
(self.0)(a) == (self.0)(b)
30+
}
31+
}
32+
33+
/// An iterator to deduplicate adjacent items in another iterator.
34+
///
35+
/// This `struct` is created by the [`dedup`], [`dedup_by`], and
36+
/// [`dedup_by_key`] methods on [`Iterator`]. See their documentation for more.
37+
///
38+
/// [`dedup`]: Iterator::dedup
39+
/// [`dedup_by`]: Iterator::dedup_by
40+
/// [`dedup_by_key`]: Iterator::dedup_by_key
41+
#[unstable(feature = "iter_dedup", issue = "83747")]
42+
#[derive(Debug)]
43+
pub struct Dedup<I: Iterator, F> {
44+
inner: I,
45+
f: F,
46+
last: Option<I::Item>,
47+
}
48+
49+
impl<I: Iterator, F> Dedup<I, F> {
50+
pub(in crate::iter) fn new(mut it: I, f: F) -> Self {
51+
let first = it.next();
52+
Self { inner: it, f, last: first }
53+
}
54+
}
55+
56+
#[unstable(feature = "iter_dedup", issue = "83747")]
57+
impl<I, F> Iterator for Dedup<I, F>
58+
where
59+
I: Iterator,
60+
I::Item: Clone,
61+
F: DedupPredicate<I::Item>,
62+
{
63+
type Item = I::Item;
64+
65+
fn next(&mut self) -> Option<Self::Item> {
66+
let last = self.last.as_ref()?;
67+
self.last = self.inner.find(|e| self.f.eq(e, last));
68+
return self.last.clone();
69+
}
70+
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod chain;
88
mod cloned;
99
mod copied;
1010
mod cycle;
11+
mod dedup;
1112
mod enumerate;
1213
mod filter;
1314
mod filter_map;
@@ -38,6 +39,10 @@ pub use self::chain::chain;
3839
pub use self::cloned::Cloned;
3940
#[stable(feature = "iter_copied", since = "1.36.0")]
4041
pub use self::copied::Copied;
42+
#[unstable(feature = "iter_dedup", issue = "83747")]
43+
pub use self::dedup::Dedup;
44+
#[unstable(feature = "iter_dedup", issue = "83747")]
45+
pub use self::dedup::{DedupEq, DedupKey};
4146
#[stable(feature = "iterator_flatten", since = "1.29.0")]
4247
pub use self::flatten::Flatten;
4348
#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]

library/core/src/iter/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,8 @@ pub use self::adapters::{
414414
Chain, Cycle, Enumerate, Filter, FilterMap, FlatMap, Fuse, Inspect, Map, Peekable, Rev, Scan,
415415
Skip, SkipWhile, Take, TakeWhile, Zip,
416416
};
417+
#[unstable(feature = "iter_dedup", issue = "83747")]
418+
pub use self::adapters::{Dedup, DedupEq, DedupKey};
417419
#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
418420
pub use self::adapters::{Intersperse, IntersperseWith};
419421
#[unstable(

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

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use super::super::{
66
};
77
use crate::array;
88
use crate::cmp::{self, Ordering};
9+
use crate::iter::adapters::{Dedup, DedupEq, DedupKey};
910
use crate::num::NonZero;
1011
use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
1112

@@ -1863,6 +1864,142 @@ pub trait Iterator {
18631864
Inspect::new(self, f)
18641865
}
18651866

1867+
/// Removes all but the first of consecutive repeated elements in the iterator
1868+
/// according to the [`PartialEq`] trait implementation.
1869+
///
1870+
/// For an iterator yielding infinitely many consecutive duplicates,
1871+
/// calling [`next`][Iterator::next] on this iterator may never halt.
1872+
///
1873+
/// If the iterator is sorted, this removes all duplicates.
1874+
///
1875+
/// # Examples
1876+
///
1877+
/// Basic usage:
1878+
///
1879+
/// ```
1880+
/// #![feature(iter_dedup)]
1881+
///
1882+
/// let vec = vec![1, 2, 2, 3, 2];
1883+
///
1884+
/// let mut iter = vec.into_iter().dedup();
1885+
///
1886+
/// assert_eq!(iter.next(), Some(1));
1887+
/// assert_eq!(iter.next(), Some(2));
1888+
/// assert_eq!(iter.next(), Some(3));
1889+
/// assert_eq!(iter.next(), Some(2));
1890+
/// assert_eq!(iter.next(), None);
1891+
/// ```
1892+
///
1893+
/// Example of an infinite loop:
1894+
///
1895+
/// ```no_run
1896+
/// #![feature(iter_dedup)]
1897+
///
1898+
/// // this will never terminate
1899+
/// let _ = std::iter::repeat(2).dedup().next();
1900+
/// ```
1901+
#[unstable(feature = "iter_dedup", issue = "83747")]
1902+
#[inline]
1903+
fn dedup<F>(self) -> Dedup<Self, DedupEq>
1904+
where
1905+
Self: Sized,
1906+
Self::Item: PartialEq,
1907+
{
1908+
Dedup::new(self, DedupEq)
1909+
}
1910+
1911+
/// Removes all but the first of consecutive elements in the iterator
1912+
/// satisfying a given equality relation.
1913+
///
1914+
/// The `same_bucket` function is passed a references to two elements from
1915+
/// the iterator and must determine if the elements compare equal.
1916+
///
1917+
/// For an iterator yielding infinitely many consecutive duplicates,
1918+
/// calling [`next`][Iterator::next] on this iterator may never halt.
1919+
///
1920+
/// If the iterator is sorted, this removes all duplicates.
1921+
///
1922+
/// # Examples
1923+
///
1924+
/// Basic usage:
1925+
///
1926+
/// ```
1927+
/// #![feature(iter_dedup)]
1928+
///
1929+
/// let vec = vec!["foo", "bar", "Bar", "baz", "bar"];
1930+
///
1931+
/// let mut iter = vec.into_iter().dedup_by(|a, b| a.eq_ignore_ascii_case(b));
1932+
///
1933+
/// assert_eq!(iter.next(), Some("foo"));
1934+
/// assert_eq!(iter.next(), Some("bar"));
1935+
/// assert_eq!(iter.next(), Some("baz"));
1936+
/// assert_eq!(iter.next(), Some("bar"));
1937+
/// assert_eq!(iter.next(), None);
1938+
/// ```
1939+
///
1940+
/// Example of an infinite loop:
1941+
///
1942+
/// ```no_run
1943+
/// #![feature(iter_dedup)]
1944+
///
1945+
/// // this will never terminate
1946+
/// let _ = std::iter::repeat(2).dedup_by(|a, b| a == b).next();
1947+
/// ```
1948+
#[unstable(feature = "iter_dedup", issue = "83747")]
1949+
#[inline]
1950+
fn dedup_by<F>(self, f: F) -> Dedup<Self, F>
1951+
where
1952+
Self: Sized,
1953+
F: FnMut(&Self::Item, &Self::Item) -> bool,
1954+
{
1955+
Dedup::new(self, f)
1956+
}
1957+
1958+
/// Removes all but the first of consecutive elements in the iterator
1959+
/// that resolve to the same key.
1960+
///
1961+
/// For an iterator yielding infinitely many consecutive duplicates,
1962+
/// calling [`next`][Iterator::next] on this iterator may never halt.
1963+
///
1964+
/// If the iterator is sorted, this removes all duplicates.
1965+
///
1966+
/// # Examples
1967+
///
1968+
/// Basic usage:
1969+
///
1970+
/// ```
1971+
/// #![feature(iter_dedup)]
1972+
///
1973+
/// let vec = vec![10, 20, 21, 30, 20];
1974+
///
1975+
/// let mut iter = vec.into_iter().dedup_by_key(|&i| i / 10);
1976+
///
1977+
/// assert_eq!(iter.next(), Some(10));
1978+
/// assert_eq!(iter.next(), Some(20));
1979+
/// assert_eq!(iter.next(), Some(30));
1980+
/// assert_eq!(iter.next(), Some(20));
1981+
/// assert_eq!(iter.next(), None);
1982+
/// ```
1983+
///
1984+
/// Example of an infinite loop:
1985+
///
1986+
/// ```no_run
1987+
/// #![feature(iter_dedup)]
1988+
///
1989+
/// // this will never terminate
1990+
/// let _ = std::iter::repeat(2).dedup_by_key(|&n| n).next();
1991+
/// ```
1992+
#[unstable(feature = "iter_dedup", issue = "83747")]
1993+
#[inline]
1994+
fn dedup_by_key<F, K>(self, f: F) -> Dedup<Self, DedupKey<F>>
1995+
where
1996+
Self: Sized,
1997+
F: FnMut(&Self::Item) -> K,
1998+
K: PartialEq,
1999+
{
2000+
Dedup::new(self, DedupKey(f))
2001+
}
2002+
18662003
/// Creates a "by reference" adapter for this instance of `Iterator`.
18672004
///
18682005
/// Consuming method calls (direct or indirect calls to `next`)

0 commit comments

Comments
 (0)