How to get the current item from iterator - rust

Is it possible to get the current item from an iterator in Rust?
I would like the same functionality as .next() but it wouldn't continue to the next item, it would just return the current item.
so:
fn main() {
let x = vec![1, 2, 3, 4, 5];
let iterator = x.iter(); // Create an iterator
// y is now just a single i32 from the x array
let y = iterator.next().unwrap();
// I'm looking for method that will return the current item from the iterator
// Something like iterator.current() which is not implemented for some reason.
let z = iterator.current();
}

You can wrap your iterator in Peekable:
fn main() {
let x = vec![1, 2, 3, 4, 5];
let iterator = x.iter().peekable();
let y = iterator.next().unwrap();
let z = iterator.peek();
}
peek() returns the about-to-be-yielded item, i.e. the item that will be returned next time you'll call next(). Note that it returns a reference and not an owned item.

Related

Idiomatic way to optionally add one item to an iterator? [duplicate]

Let's say I have:
let it = [1, 2, 3].into_iter();
let jt = [4, 5, 6].into_iter();
let kt = [7, 8, 9].into_iter();
Then I have boolean conditions i, j and k. I want to generate an iterator that conditionally chains it, jt and kt together based on the values of i, j and k. Can I do this with just the built-in Rust Iterator functionality?
You can make Option into an iterator.
let it = i.then_some([1, 2, 3]).into_iter().flatten();
let jt = j.then_some([4, 5, 6]).into_iter().flatten();
let kt = k.then_some([7, 8, 9]).into_iter().flatten();
let iter = it.chain(jt).chain(kt);
If the condition is false, then condition.then_some(...) will return None, making an empty iterator. Otherwise a Some(...) is returned. into_iter().flatten() will transform Option<impl IntoIterator<Item=T>> to impl Iterator<Item=T>.
You're going to run into a slight issue if you want to use bare iterators:
If you write the following:
let iter = [1, 2, 3].into_iter();
let iter = if some_condition {
iter.chain([4, 5, 6])
} else {
iter
}
You'll get an error which boils down to this:
= note: expected struct `std::iter::Chain<std::array::IntoIter<_, _>, std::array::IntoIter<{integer}, 3>>`
found struct `std::array::IntoIter<_, _>`
iter has type IntoIter, but iter.chain() has type Chain<IntoIter, ...>
To get around this, you have a few options:
you can use a trait object, which behaves a bit like an interface from languages like Java, but loses some performance:
let iter = [1, 2, 3].into_iter();
let mut iter: Box<dyn Iterator<Item = i32>> = Box::new(iter);
if some_condition {
iter = Box::new(iter.chain([4, 5, 6]));
}
or, probably a better solution, if you can sacrifice laziness, is to just use a Vec:
// save heap allocations by pre-allocating the whole vec
let len = if some_condition { 6 } else { 3 };
let mut items = Vec::with_capacity(len);
items.extend([1, 2, 3]);
if some_condition {
items.extend([4, 5, 6]);
}
This is a good use for the either crate. Either implements Iterator when both the left and right sides also implement Iterator, so it can be easily used to chain iterators together.
Given any three iterators it, jt, and kt that iterate over the same Item, with accompanying booleans i, j, and k, you can write a function that chains them together like this:
use either::Either;
use std::iter;
fn chain<'a, I, J, K, Item>(
it: I,
jt: J,
kt: K,
i: bool,
j: bool,
k: bool,
) -> iter::Chain<
iter::Chain<Either<I, iter::Empty<Item>>, Either<J, iter::Empty<Item>>>,
Either<K, iter::Empty<Item>>,
>
where
I: Iterator<Item = Item>,
J: Iterator<Item = Item>,
K: Iterator<Item = Item>,
{
let iter = if i {
Either::Left(it)
} else {
Either::Right(iter::empty())
};
let iter = iter.chain(if j {
Either::Left(jt)
} else {
Either::Right(iter::empty())
});
let iter = iter.chain(if k {
Either::Left(kt)
} else {
Either::Right(iter::empty())
});
iter
}
Calling this function will result in an iterator conditional on the input. For example, calling
let it = [1, 2, 3].into_iter();
let jt = [4, 5, 6].into_iter();
let kt = [7, 8, 9].into_iter();
chain(it, jt, kt, true, false, true).collect::<Vec<_>>();
gives
[1, 2, 3, 7, 8, 9]
as expected.
You can try it using this playground.

How to iterate inside an iteration?

So basically, I want to do this
for i=0;i<x.len()-1
for j=i;j<x.len
//do stuff with x[j] and x[i] at the same time
For example, I want to use the same tehnique as sorting using 2 for loops, comparing element with element and interchange them. I do not want to sort however, just gave this example for better understanding.
Can i somehow do like:
for x in vec.iter()
for y in x.next()
or something like this?
Also, can I somehow remember the position of a certain element while iterating?
Thank you!
You could use ranges
for i in 0..vec.len()-1 {
for j in i..vec.len() {
// do something with vec[i] and vec[j]
}
}
Your suggested code:
for x in vec.iter()
for y in x.next()
wouldn't work even if it were syntactically valid because x is not an iterator, it's an element of vec. To get at the iterator, you need to store it in a variable and desugar the for loop into while let:
let mut iter = v.iter();
while let Some(x) = iter {
// ...
}
Now that we have an explicit iter, we can make the inner loop iterate over the remaining items. We can't just iterate over iter because that would exhaust it for the outer loop, but we can clone it to obtain a copy of the outer iterator at its current position:
let mut iter = v.iter();
while let Some(x) = iter {
for y in iter.clone() {
// ...
}
}
Note that we don't need to explicitly call iter.next() before the inner loop, as the first item will have already been spent by the outer loop, and the inner loop will naturally observe only the remaining items of each iteration.
Complete code would look like this:
let v = vec![1, 2, 3];
let mut iter = v.iter();
while let Some(x) = iter.next() {
println!("x = {}", x);
for y in iter.clone() {
println!(" y = {}", y);
}
}
Output:
x = 1
y = 2
y = 3
x = 2
y = 3
x = 3

Does Rust implicitly convert direct slices to references of slices?

For example, are these the same, or does doing let x = myar[2] clone the number 3 and put it in x?
let myar = [1, 2, 3, 4, 5];
let x = myar[2];
let x = &myar[2];
No.
let x = myar[2]; does indeed copy the value 3 and store it in x, while let x = &myar[2]; stores a reference to the value 3 in myar.
Note that the only reason let x = myar[2]; works at all is because i32 implements the Copy trait. If we had an array storing a type that does not implement the Copy trait, you wouldn't be able to do that at all. For example:
struct Number {
num: i32,
}
impl Number {
fn new(num: i32) -> Number {
Number { num }
}
}
// Note that Number does not implement the Copy trait
fn main() {
let number_list = [Number::new(1), Number::new(2), Number::new(3)];
// This does not work:
let _x = number_list[1];
// This does work:
let _x = &number_list[1];
}

Retrieve the state in scan() iterator?

To obtain the partial sums of a sequence of integers, I can use scan() on the iterator like this:
let partial: Box<[u32]> =
list
.iter()
.scan(0, |st, elem| {
let ret = *st;
*st += elem;
Some(ret)
})
.collect();
The above code works well, but I'm trying to modify it to give me the total sum as well.
Something like:
let (partial, total): (Box<[u32]>, u32) =
list
.iter()
.scan(0, |st, elem| {
// TODO
})
.collect();
It seems like I would just need to obtain the eventual value of st, and the iterator should already know it's value. However, I can't seem to find a way to retrieve that value, short of doing a second iteration over the whole sequence (e.g. with fold()).
Is there a way to find the partial sums and the total sum in a single pass?
Include the total sum in the scan, but then split off the last value.
use std::iter;
fn main() {
let list = vec![1, 2, 3, 4];
// Add zero at the start to emulate what you had before
let partial: Box<[u32]> = iter::once(0)
.chain(list.iter().scan(0, |st, elem| {
*st += elem;
Some(*st)
}))
.collect();
// unwrap since with the added zero, the slice will always be non-empty
let (total, partial) = partial.split_last().unwrap();
println!("partial sums: {:?}", partial);
println!("total sum: {}", total);
}
(playground)
Or using successors():
fn main() {
use std::iter::successors;
let list = vec![1, 2, 3, 4];
let mut iter = list.iter();
let partial: Vec<_> = successors(Some(0), |n| iter.next().map(|i| n + i)).collect();
// unwrap since with the added zero, the slice will always be non-empty
let (total, partial) = partial.split_last().unwrap();
assert_eq!(partial, &[0, 1, 3, 6]);
assert_eq!(total, &10);
}
(playground)
You must decide what you want to do in the closure.
As it stands in your code, you remember ret = *st which is the accumulator's value before the addition takes place, and you return Some(ret). Thus, the first item you get in the result is currently 0.
If you want the value after the sums, you should just return Some(*st), which is the updated accumulator's value after the addition.

How to get the index of the current element being processed in the iteration without a for loop?

I have read How to iterate a Vec<T> with the indexed position? where the answer is to use enumerate in a for-loop.
But if I don't use a for-loop like this:
fn main() {
let v = vec![1; 10]
.iter()
.map(|&x| x + 1 /* + index */ ) // <--
.collect::<Vec<_>>();
print!("v{:?}", v);
}
How could I get the index in the above closure?
You can also use enumerate!
let v = vec![1; 10]
.iter()
.enumerate()
.map(|(i, &x)| x + i)
.collect::<Vec<_>>();
println!("v{:?}", v); // prints v[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Let's see how this works. Iterator::enumerate returns Enumerate<Self>. That type also implements Iterator:
impl<I> Iterator for Enumerate<I>
where
I: Iterator,
{
type Item = (usize, <I as Iterator>::Item);
// ...
}
As you can see, the new iterator yields tuples of the index and the original
value.
You can simply use enumerate:
fn main() {
let v = vec![1; 10]
.iter()
.enumerate()
.map(|(i, x)| i + x)
.collect::<Vec<_>>();
print!("v{:?}", v);
}
The reason for this is because the for loop takes an enumerator:
In slightly more abstract terms:
for var in expression {
code
}
The expression is an iterator.

Resources