Enumerate over indices without values in rust - rust

Is there a cleaner way to do this?
for i in collection.iter().enumerate().map(|(i, _)| i) {...}
In other words I'm looking for a method like enumerate but which only gives the indices, not the values. Something like
for i in collection.iter().indices() {...}
Does such a method exist?

I want to chain a bunch of other methods but I don't want to type |(i, _)| in each closure, I want to just type |i|
[...]
Does such a method exist?
No, but you can write an extension trait that provides one (playground):
trait IndicesExt<I> {
fn indices(self) -> Indices<I>;
}
struct Indices<I> {
next: usize,
iter: I,
}
impl<I: Iterator> IndicesExt<I> for I {
fn indices(self) -> Indices<I> {
Indices {
next: 0,
iter: self,
}
}
}
impl<I: Iterator> Iterator for Indices<I> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
if let Some(_) = self.iter.next() {
let current = self.next;
self.next += 1;
Some(current)
} else {
None
}
}
}
The implementation can be simplified by reusing the Enumerate iterator returned by Iterator::enumerate() (playground):
struct Indices<I>(std::iter::Enumerate<I>);
impl<I: Iterator> IndicesExt<I> for I {
fn indices(self) -> Indices<I> {
Indices(self.enumerate())
}
}
impl<I: Iterator> Iterator for Indices<I> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
self.0.next().map(|(idx, _)| idx)
}
}

Related

In Rust, is it OK for an (non-moving) iter to return owned values rather than references?

For example, this works:
pub struct SquareVecIter<'a> {
current: f64,
iter: core::slice::Iter<'a, f64>,
}
pub fn square_iter<'a>(vec: &'a Vec<f64>) -> SquareVecIter<'a> {
SquareVecIter {
current: 0.0,
iter: vec.iter(),
}
}
impl<'a> Iterator for SquareVecIter<'a> {
type Item = f64;
fn next(&mut self) -> Option<Self::Item> {
if let Some(next) = self.iter.next() {
self.current = next * next;
Some(self.current)
} else {
None
}
}
}
// switch to test module
#[cfg(test)]
mod tests_2 {
use super::*;
#[test]
fn test_square_vec() {
let vec = vec![1.0, 2.0];
let mut iter = square_iter(&vec);
assert_eq!(iter.next(), Some(1.0));
assert_eq!(iter.next(), Some(4.0));
assert_eq!(iter.next(), None);
}
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=531edc40dcca4a79d11af3cbd29943b7
But if I have to return references to self.current then I can't get the lifetimes to work.
Yes.
An Iterator cannot yield elements that reference itself simply due to how the trait is designed (search "lending iterator" for more info). So even if you wanted to return Some(&self.current) and deal with the implications therein, you could not.
Returning an f64 (non-reference) is perfectly acceptable and would be expected because this is a kind of generative iterator. And you wouldn't need to store current at all:
pub struct SquareVecIter<'a> {
iter: core::slice::Iter<'a, f64>,
}
pub fn square_iter<'a>(vec: &'a Vec<f64>) -> SquareVecIter<'a> {
SquareVecIter {
iter: vec.iter(),
}
}
impl<'a> Iterator for SquareVecIter<'a> {
type Item = f64;
fn next(&mut self) -> Option<Self::Item> {
if let Some(next) = self.iter.next() {
Some(next * next)
} else {
None
}
}
}
For an example of this in the standard library, look at the Chars iterator for getting characters of a string. It keeps a reference to the original str, but it yields owned chars and not references.
What #kmdreko says, of course.
I just wanted to add a couple of nitpicks:
The pattern of the if let Some(...) = ... {Some} else {None} is so common that it made its way into the standard library as the .map function.
Taking a &Vec<f64> is an antipattern. Use &[f64] instead. It is more general without any drawbacks.
All of your lifetime annotations (except of the one in the struct definition) can be derived automatically, so you can simply omit them.
pub struct SquareVecIter<'a> {
iter: core::slice::Iter<'a, f64>,
}
pub fn square_iter(vec: &[f64]) -> SquareVecIter {
SquareVecIter { iter: vec.iter() }
}
impl Iterator for SquareVecIter<'_> {
type Item = f64;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|next| next * next)
}
}

Iterator that skips every nth element

Rather than taking every Nth element from an iterator which I can do with Iterator::step_by, I would like to skip every Nth element. How can I achieve this idiomatically? Is there maybe even a standard library or itertools function?
This is what I came up with to skip every 7th say. It requires enumerate, filter, and map, though one could use a filter_map instead of the latter two.
(0..100).enumerate()
.filter(|&(i, x)| (i + 1) % 7 != 0)
.map(|(i, x)| x);
How could I cast this into a function so that I could simply write:
(0..100).skip_every(7)
If you want to get the exact interface you asked for, your best option at this time is to implement a custom iterator adapter type. Here's a basic version of such a type:
pub struct SkipEvery<I> {
inner: I,
every: usize,
index: usize,
}
impl<I> SkipEvery<I> {
fn new(inner: I, every: usize) -> Self {
assert!(every > 1);
let index = 0;
Self {
inner,
every,
index,
}
}
}
impl<I: Iterator> Iterator for SkipEvery<I> {
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
if self.index == self.every - 1 {
self.index = 1;
self.inner.nth(1)
} else {
self.index += 1;
self.inner.next()
}
}
}
pub trait IteratorSkipEveryExt: Iterator + Sized {
fn skip_every(self, every: usize) -> SkipEvery<Self> {
SkipEvery::new(self, every)
}
}
impl<I: Iterator + Sized> IteratorSkipEveryExt for I {}
(Playground)
A more complete implementation could also add optimized versions of further Iterator methods, as well as implementations of DoubleEndedIterator and ExactSizeIterator -- see the implementation of StepBy as an example.
Your code is pretty easy to turn into a function:
fn skip_every<I: Iterator> (iter: I, n: usize) -> impl Iterator<Item = <I as Iterator>::Item> {
iter.enumerate()
.filter_map(move |(i, v)| if (i + 1) % n != 0 { Some (v) } else { None })
}
fn main() {
println!("{:?}", skip_every (0..20, 7).collect::<Vec<_>>());
}
Playground
Or avoiding the expensive modulo:
fn skip_every2<I: Iterator> (iter: I, n: usize) -> impl Iterator<Item = <I as Iterator>::Item> {
iter.zip ((0..n).rev().cycle()).filter_map (|(v, i)| if i != 0 { Some (v) } else { None })
}
Playground

How can I intersperse a rust iterator with a value every n items?

I have an iterator of characters, and I want to add a newline every N characters:
let iter = "abcdefghijklmnopqrstuvwxyz".chars();
let iter_with_newlines = todo!();
let string: String = iter_with_newlines.collect();
assert_eq("abcdefghij\nklmnopqrst\nuvwxyz", string);
So basically, I want to intersperse the iterator with a newline every n characters. How can I do this?
Some Ideas I had
It would be great if I could do something like this, where chunks would be a method to make Iterator<T> into Iterator<Iterator<T>: iter.chunks(10).intersperse('\n').flatten()
It would also be cool if I could do something like this: iter.chunks.intersperseEvery(10, '\n'), where intersperseEvery is a method that would only intersperse the value every n items.
You can do it without temporary allocation using enumerate and flat_map:
use either::Either;
fn main() {
let iter = "abcdefghijklmnopqrstuvwxyz".chars();
let iter_with_newlines = iter
.enumerate()
.flat_map(|(i, c)| {
if i % 10 == 0 {
Either::Left(['\n', c].into_iter())
} else {
Either::Right(std::iter::once(c))
}
})
.skip(1); // The above code add a newline in first position -> skip it
let string: String = iter_with_newlines.collect();
assert_eq!("abcdefghij\nklmnopqrst\nuvwxyz", string);
}
Playground
Here's what I ended up doing:
// src/intersperse_sparse.rs
use core::iter::Peekable;
/// An iterator adaptor to insert a particular value
/// every n elements of the adapted iterator.
///
/// Iterator element type is `I::Item`
pub struct IntersperseSparse<I>
where
I: Iterator,
I::Item: Clone,
{
iter: Peekable<I>,
step_length: usize,
index: usize,
separator: I::Item,
}
impl<I> IntersperseSparse<I>
where
I: Iterator,
I::Item: Clone,
{
#[allow(unused)] // Although this function isn't explicitly exported, it is called in the default implementation of the IntersperseSparseAdapter, which is exported.
fn new(iter: I, step_length: usize, separator: I::Item) -> Self {
if step_length == 0 {
panic!("Chunk size cannot be 0!")
}
Self {
iter: iter.peekable(),
step_length,
separator,
index: 0,
}
}
}
impl<I> Iterator for IntersperseSparse<I>
where
I: Iterator,
I::Item: Clone,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
if self.index == self.step_length && self.iter.peek().is_some() {
self.index = 0;
Some(self.separator.clone())
} else {
self.index += 1;
self.iter.next()
}
}
}
/// An iterator adaptor to insert a particular value created by a function
/// every n elements of the adapted iterator.
///
/// Iterator element type is `I::Item`
pub struct IntersperseSparseWith<I, G>
where
I: Iterator,
G: FnMut() -> I::Item,
{
iter: Peekable<I>,
step_length: usize,
index: usize,
separator_closure: G,
}
impl<I, G> IntersperseSparseWith<I, G>
where
I: Iterator,
G: FnMut() -> I::Item,
{
#[allow(unused)] // Although this function isn't explicitly exported, it is called in the default implementation of the IntersperseSparseAdapter, which is exported.
fn new(iter: I, step_length: usize, separator_closure: G) -> Self {
if step_length == 0 {
panic!("Chunk size cannot be 0!")
}
Self {
iter: iter.peekable(),
step_length,
separator_closure,
index: 0,
}
}
}
impl<I, G> Iterator for IntersperseSparseWith<I, G>
where
I: Iterator,
G: FnMut() -> I::Item,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
if self.index == self.step_length && self.iter.peek().is_some() {
self.index = 0;
Some((self.separator_closure)())
} else {
self.index += 1;
self.iter.next()
}
}
}
/// Import this trait to use the `iter.intersperse_sparse(n, item)` and `iter.intersperse_sparse(n, ||item)` on all iterators.
pub trait IntersperseSparseAdapter: Iterator {
fn intersperse_sparse(self, chunk_size: usize, separator: Self::Item) -> IntersperseSparse<Self>
where
Self: Sized,
Self::Item: Clone,
{
IntersperseSparse::new(self, chunk_size, separator)
}
fn intersperse_sparse_with<G>(
self,
chunk_size: usize,
separator_closure: G,
) -> IntersperseSparseWith<Self, G>
where
Self: Sized,
G: FnMut() -> Self::Item,
{
IntersperseSparseWith::new(self, chunk_size, separator_closure)
}
}
impl<I> IntersperseSparseAdapter for I where I: Iterator {}
To use it:
// src/main.rs
mod intersperse_sparse;
use intersperse_sparse::IntersperseSparseAdapter;
fn main() {
let string = "abcdefg";
let new_string: String = string.chars().intersperse_sparse(3, '\n').collect();
assert_eq!(new_string, "abc\ndef\ng");
}
If you don't particularly care about performance, you can use chunks from itertools, collect the chunks into Vecs, and then intersperse your element as a single-element Vec, just to flatten the whole thing finally.
use itertools::Itertools;
iter
.chunks(3)
.into_iter()
.map(|chunk| chunk.collect::<Vec<_>>())
.intersperse(vec![','])
.flat_map(|chunk| chunk.into_iter())
.collect::<String>();
Playground
Other than that, consider writing your own iterator extension trait, just like itertools is one?
Build an Iterator with from_fn:
let mut iter = "abcdefghijklmnopqrstuvwxyz".chars().peekable();
let mut count = 0;
let iter_with_newlines = std::iter::from_fn(move || match iter.peek() {
Some(_) => {
if count < 10 {
count += 1;
iter.next()
} else {
count = 0;
Some('\n')
}
}
None => None,
});
assert_eq!(
"abcdefghij\nklmnopqrst\nuvwxyz",
iter_with_newlines.collect::<String>()
);
Playground

Extending Iterator for dynamic dispatch

I want to extend the Iterator trait with some convenience function. For example
trait BetterIterator: Iterator {
fn skip_bad(&mut self);
}
This can be achieved like this:
struct Iter {}
impl Iterator for Iter {
type Item = ();
fn next(&mut self) -> Option<()> { None }
}
impl BetterIterator for Iter {
fn skip_bad(&mut self) {}
}
fn make_iter() -> Box<dyn BetterIterator<Item=()>> {
Box::new( Iter {} )
}
fn main()
{
let mut iter = make_iter();
iter.skip_bad();
for _item in iter {
// ...
}
}
What is unusual, here, is the dynamic dispatch in make_iter.
Now, it would be much nicer if skip_bad could be chained, e.g.
for _item in make_iter().skip_bad() {
// ...
}
That means BetterIterator becomes
trait BetterIterator: Iterator {
fn skip_bad(&mut self) -> &mut Self;
}
impl BetterIterator for Iter {
fn skip_bad(&mut self) -> &mut Self { self }
}
But then the compiler complains "the trait BetterIterator cannot be made into an object".
Is it correct that the violated rule in Object Safety is "Dispatchable functions require: ...Be a method that does not use Self except in the type of the receiver."?
There is no way out of this, is there?
If dynamic dispatch is your goal you can return a mutable reference to a dyn BetterIterator instead.
trait BetterIterator: Iterator {
fn skip_bad(&mut self) -> &mut dyn BetterIterator<Item = Self::Item>;
}
impl BetterIterator for Iter {
fn skip_bad(&mut self) -> &mut dyn BetterIterator<Item = Self::Item> { self }
}

How to pass on closures through multiple sctructs and functions

I have a hierarchy of structs where I need to call a method in the topmost struct from an Iterator::next implementation at the lowest level.
Current implementation is as follows:
Functional abstract:
pub struct TopLevel {
answer: usize,
}
pub struct MidLevelIter<'mli> {
count: usize,
top_level: &'mli TopLevel,
}
pub struct MidLevel<'ml> {
top_level: &'ml TopLevel,
}
pub struct LowestLevelIter<'lli> {
count: usize,
top_level: &'lli TopLevel,
}
impl TopLevel {
pub fn new() -> Self {
Self { answer: 42 }
}
pub fn iter(&self) -> MidLevelIter<'_> {
MidLevelIter {
count: 1,
top_level: self,
}
}
fn calculate(&self, _: usize) -> &usize {
&self.answer
}
}
impl<'mli> Iterator for MidLevelIter<'mli> {
type Item = MidLevel<'mli>;
fn next(&mut self) -> Option<Self::Item> {
if self.count < 2 {
self.count = 2;
Some(MidLevel {
top_level: self.top_level,
})
} else {
None
}
}
}
impl<'lli> Iterator for LowestLevelIter<'lli> {
type Item = &'lli usize;
fn next(&mut self) -> Option<Self::Item> {
if self.count < 2 {
self.count = 2;
Some(self.top_level.calculate(self.count))
} else {
None
}
}
}
impl<'ml> MidLevel<'ml> {
pub fn iter(&self) -> LowestLevelIter<'ml> {
LowestLevelIter {
count: 1,
top_level: self.top_level,
}
}
}
fn main() {
let collector = TopLevel::new();
for pc in collector.iter() {
for sc in pc.iter() {
println!("SC={}", sc);
}
}
}
This works fine, but it kind of bothers me that I have to pass a reference to TopLevel through all these structs.
So, my idea was to pass only the required method as a closure. That way, the lower levels need not to know anything about the TopLevel construct.
the following approach, however, fails because of "cannot move out of self.mapper which is behind a mutable reference".
pub struct TopLevel {
answer: usize,
}
pub struct MidLevelIter<'mli> {
count: usize,
mapper: Box<dyn Fn(usize) -> &'mli usize + 'mli>,
}
pub struct MidLevel<'ml> {
mapper: Box<dyn Fn(usize) -> &'ml usize + 'ml>,
}
pub struct LowestLevelIter<'lli> {
count: usize,
mapper: Box<dyn Fn(usize) -> &'lli usize + 'lli>,
}
impl TopLevel {
pub fn new() -> Self {
Self { answer: 42 }
}
pub fn iter(&self) -> MidLevelIter<'_> {
MidLevelIter {
count: 1,
mapper: Box::new(self.mapper()),
}
}
fn calculate(&self, _: usize) -> &usize {
&self.answer
}
fn mapper<'m>(&'m self) -> impl Fn(usize) -> &'m usize {
move |secondary_index| self.calculate(secondary_index)
}
}
impl<'mli> Iterator for MidLevelIter<'mli> {
type Item = MidLevel<'mli>;
fn next(&mut self) -> Option<Self::Item> {
if self.count < 2 {
self.count = 2;
Some(MidLevel {
mapper: self.mapper,
})
} else {
None
}
}
}
impl<'lli> Iterator for LowestLevelIter<'lli> {
type Item = &'lli usize;
fn next(&mut self) -> Option<Self::Item> {
if self.count < 2 {
self.count = 2;
Some((self.mapper)(self.count))
} else {
None
}
}
}
impl<'ml> MidLevel<'ml> {
pub fn iter(&self) -> LowestLevelIter<'ml> {
LowestLevelIter {
count: 1,
mapper: self.mapper,
}
}
}
fn main() {
let collector = TopLevel::new();
for pc in collector.iter() {
for sc in pc.iter() {
println!("SC={}", sc);
}
}
}
Although I can understand what the compiler tells me there, I don't see how to circumvent it.
Traits are the answer to my problem.
Basically, on the lowest level I just wanted to perform a transformation of some sort on the items of the iteration. Although closures looked suitable for that, Rust provides another feature to accomplish this: Traits.
On the lowest level, I want to convert a numerical index to a key reference. So make a trait for it:
trait IndexToKey {
fn calculate(&self, _: usize) -> &usize;
}
This trait can now be passed on, e.g.:
pub struct MidLevelIter<'mli> {
count: usize,
mapper: &'mli dyn IndexToKey,
}
Originally, my TopLevel struct provided the logic, so let's implement the trait:
impl IndexToKey for TopLevel {
fn calculate(&self, _ix: usize) -> &usize {
&self.answer
}
}
Now we can pass a reference to trait implementation down to the lowest level, which now simply performs the conversion:
impl<'lli> Iterator for LowestLevelIter<'lli> {
type Item = &'lli usize;
fn next(&mut self) -> Option<Self::Item> {
if self.count < 2 {
self.count = 2;
Some(self.mapper.calculate(self.count))
} else {
None
}
}
}
No lifetime issues, no disclosure or dependency on implementation details of the TopLevel structs at the other levels.
Implementation on the Rust playground

Resources