Using an iterator, how do I skip a number of values and then display the rest? - iterator

Random access to the elements is not allowed.
let vec = vec![1,2,3,4,5,6,7,8,9,0];
let n = 3;
for v in vec.iter().rev().take(n) {
println!("{}", v);
}
// this printed: 0, 9, 8
// need: 8, 9, 0
for v in vec.iter().rev().skip(n).rev() does not work.

I think the code you wrote does what you're asking it to.
You are reversing the vec with rev() and then you're taking the first 3 elements of the reversed vector (therefore 0, 9, 8)
To obtain the last 3 in non-reversed order you can skip to the end of the vector minus 3 elements, without reversing it:
let vec = vec![1,2,3,4,5,6,7,8,9,0];
let n = vec.len() - 3;
for v in vec.iter().skip(n) {
println!("{}", v);
}

Neither skip nor take yield DoubleEndIterator, you have to either:
skip, which is O(N) in the number of skipped items
collect the result of .rev().take(), and then rev it, which is O(N) in the number of items to be printed, and requires allocating memory for them
The skip is obvious, so let me illustrate the collect:
let vec = vec![1,2,3,4,5,6,7,8,9,0];
let vec: Vec<_> = vec.iter().rev().take(3).collect();
for v in vec.iter().rev() {
println!("{}", v);
}
Of course, the inefficiency is due to you shooting yourself in the foot by avoiding random access in the first place...

Based on the comments, I guess you want to iterate specifically through the elements of a Vec or slice. If that is the case, you could use range slicing, as shown below:
let vec = vec![1,2,3,4,5,6,7,8,9,0];
let n = vec.len() - 3;
for v in &vec[n..] {
println!("{}", v);
}
The big advantage of this approach is that it doesn't require to skip through elements you are not interested in (which may have a big cost if not optimized away). It will just make a new slice and then iterate through it. In other words, you have the guarantee that it will be fast.

Related

How to make an ordered list of boolean array permutations with a given number of trues

Is there an efficient method to generate all possible arrays of booleans with a given number of "true" values?
Right now I'm incrementing a number and checking if its binary representation has the given number of 1s (and if so, adding that array). But this becomes extremely slow for larger givens.
This is the kind of input-output that I'm looking for:
(length: 4, trues: 2) -> [[1,1,0,0],[1,0,1,0],[0,1,1,0],[1,0,0,1],[0,1,0,1],[0,0,1,1]]
The trouble is doing it in less than O(2^N), and so that they're ordered as the little endian binary representations would be.
If it helps the length would be a fixed number at compile time (currently it's 64). I wrote it as an input because I might have to increase it to 128, but it won't vary during runtime.
You can define a recursive solution to this problem.
fn solution(length: u32, trues: u32) -> Vec<Vec<bool>>;
How do we formulate this function recursively? Let's think about the last element of the output arrays. If that last element is false, then the amount of true elements in the 0..length-1 elements must be trues. If that last element is true, then the amount of true elements in the 0..length-1 elements must be trues-1.
So we can just answer the problem for (length-1, trues) and then extend them all with false, and answer the problem for (length-1, trues-1) and extend them all with true, and then we can combine the result (putting the ends-with-true case first for little endian ordering). Adding in some base cases, we get the following code:
fn solution(length: u32, trues: u32) -> Vec<Vec<bool>> {
if trues > length {
// no candidate arrays exist
return vec![];
}
if length == 0 {
// one array exists: the empty array
return vec![vec![]];
}
if trues == 0 {
// one array exists: the all-false array
return vec![vec![false; length as usize]];
}
let mut result = Vec::new();
for mut ones in solution(length-1, trues-1) {
ones.push(true);
result.push(ones);
}
for mut zeroes in solution(length-1, trues) {
zeroes.push(false);
result.push(zeroes);
}
result
}
If the time complexity for solution(L, T) is O(S(L,T)), then the time complexity of solution(L,T) can be recursively expressed as O(S(L-1,T-1) + S(L-1,T)), with the base cases S(0,0) = 1, S(L,L+1)=1, S(L,0) = L. This is the best achievable time complexity, since S(L,T) = S(L-1,T-1) + S(L-1,T) is also the recursive formula for how many arrays of length L and true-count T exist. This is also the same recurrence formula as the binomial recurrence equation, but the base cases are different. I will leave computing the time complexity as an exercise to the reader, and there are a couple of trivial optimizations to the above code that can be done to bring down the computation time further.

How do I chain operators over lists in rust? Looking for equivalent to kotlin code

I have the following code in kotlin and I'm trying to find a rust equivalent, but don't understand the chaining mechanism in rust to convert.
val windowSize = 2
val result = listOf(1, 2, 3, 4, 5, 6)
.windowed(windowSize, 1) ; [[1,2], [2,3], [3,4], [4,5], [5,6]]
.map { it.sum() } ; [ 3, 5, 7, 9, 11]
.windowed(2, 1) ; [[3,5], [5,7], [7,9], [9,11] ]
.count { it[0] < it[1] } ; 4
;; result = 4, as there are 4 sequences that have first number less than 2nd,
;; when considering a sliding window over the original data of 2 items at a time.
It just takes a list of integers, splits them into pairs (but the windowSize will be a function parameter), sums those groups, splits the sums into pairs again, and finds where each second element is bigger than the previous, so finding increasing values over moving windows.
I'm converting this to the rust equivalent, but struggling to understand how to chain operations together.
What I've got so far is:
let input = [1, 2, 3, 4, 5, 6];
input.windows(2)
.map(|es| es.iter().sum())
// what goes here to do the next windows(2) operation?
.for_each(|x: u32| println!("{}", x));
I can "for_each" over the map to do things on the iteration, but I can't split it with another "windows()", or don't know the magic to make that possible. IntelliJ is showing me the return type from map is impl Iterator<Item=?>
Can anyone enlighten me please? I am an absolute beginner on rust, so this is undoubtedly to do with my understanding of the language as a whole.
The Itertools crate provides a reasonably convenient way to do this with the tuple_windows method.
use itertools::Itertools;
fn main() {
let input = [1i32, 2, 3, 4, 5, 6];
let output: usize = input
.windows(2)
.map(|es| es.iter().sum::<i32>())
.tuple_windows()
.filter(|(a, b)| a < b)
.count();
println!("{}", output);
}
Playground
The standard library does not have a way to do this without collecting the iterator first, which requires two passes through the data.
It is a bit convoluted to chain everything. You need to collect into a vec so you can access windows again. Then you can flat_map the windows to array references (taken from this other answer) to complete what you want to do:
fn main() {
let input = [1usize, 2, 3, 4, 5, 6];
let res = input
.windows(2)
.map(|es| es.iter().sum::<usize>())
.collect::<Vec<_>>()
.windows(2)
.flat_map(<[usize; 2]>::try_from)
.filter(|[a, b]| a < b)
.count();
println!("{}", res);
}
Playground
Note: Nightly feature array_windows that use const generic allow to remove the .flat_map(<&[usize; 2]>::try_from) call
As stated in #Aiden4's answer, the best solution is to use itertools::tuple_windows. It is however possible using just the standard library and without collecting to an intermediate vector using Iterator::scan:
fn main() {
let input = [1i32, 2, 3, 4, 5, 6];
let output: usize = input
.windows(2)
.map(|es| es.iter().sum())
.scan(0, |prev, cur| {
let res = (*prev, cur);
*prev = cur;
Some(res)
})
.skip(1)
.filter(|(a, b)| a < b)
.count();
println!("{}", output);
}
Playground
Using std and stable only:
fn main() {
let input = [1i32, 2, 3, 4, 5, 6];
let mut iter = input.windows(2).map(|es| es.iter().sum::<i32>());
let n = if let Some(mut prev) = iter.next() {
iter.map(|i| {
let ret = (prev, i);
prev = i;
ret
})
.filter(|(a, b)| a < b)
.count()
} else {
0
};
println!("{}", n);
}
This should be very fast.

Return a moving window of elements resulting from an iterator of Vec<u8>

I'm trying to figure out how to return a window of elements from a vector that I've first filtered without copying it to a new vector.
So this is the naive approach which works fine but I think will end up allocating a new vector from line 5 which I don't really want to do.
let mut buf = Vec::new();
file.read_to_end(&mut buf);
// Do some filtering of the read file and create a new vector for subsequent processing
let iter = buf.iter().filter(|&x| *x != 10 && *x != 13);
let clean_buf = Vec::from_iter(iter);
for iter in clean_buf.windows(13) {
print!("{}",iter.len());
}
Alternative approach where I could use a chain()? to achieve the same thing without copying into a new Vec
for iter in buf.iter().filter(|&x| *x != 10 && *x != 13) {
let window = ???
}
You can use Vec::retain instead of filter for this, which allows you to keep your Vec:
fn main() {
let mut buf = vec![
8, 9, 10, 11, 12, 13, 14,
8, 9, 10, 11, 12, 13, 14,
8, 9, 10, 11, 12, 13, 14,
];
println!("{:?}", buf);
buf.retain(|&x| x != 10 && x != 13);
println!("{:?}", buf);
for iter in buf.windows(13) {
print!("{}, ", iter.len());
}
println!("");
}
I don't see how this would be possible. You say:
elements from a vector that I've first filtered
But once you've filtered a vector, you don't have a vector anymore - you just have an Iterator. Iterators only have the concept of the next item.
To be most efficient, you'd have to create a small buffer of the size of your window. Unfortunately, you cannot write an iterator that returns a reference to itself, so you'd have to pass in a buffer to a hypothetical Iterator::windows method. In that case, you'd run into the problem of having a mutable reference (so you could populate the buffer) and an immutable reference (so you could return a slice), which won't fly.
The only close solution I can think of is to have multiple iterators over the same vector that you then zip together:
fn main() {
let nums: Vec<u8> = (1..100).collect();
fn is_even(x: &&u8) -> bool { **x % 2 == 0 }
let a = nums.iter().filter(is_even);
let b = nums.iter().filter(is_even).skip(1);
let c = nums.iter().filter(is_even).skip(2);
for z in a.zip(b).zip(c).map(|((a, b), c)| (a,b,c)) {
println!("{:?}", z);
}
}
This has the distinct downside of needing to apply the filtering condition multiple times, and the ugliness of the nested zips (you can fix the latter with use of itertools though).
Personally, I'd probably just collect into a Vec, as you have already done.

How do I convert a list of Option<T> to a list of T when T cannot be copied? [duplicate]

This question already has an answer here:
How do I avoid unwrap when converting a vector of Options or Results to only the successful values?
(1 answer)
Closed 4 years ago.
How do I take a Vec<Option<T>>, where T cannot be copied, and unwrap all the Some values?
I run into an error in the map step. I'm happy to move ownership of the original list and "throw away" the Nones.
#[derive(Debug)]
struct Uncopyable {
val: u64,
}
fn main() {
let num_opts: Vec<Option<Uncopyable>> = vec![
Some(Uncopyable { val: 1 }),
Some(Uncopyable { val: 2 }),
None,
Some(Uncopyable { val: 4 }),
];
let nums: Vec<Uncopyable> = num_opts
.iter()
.filter(|x| x.is_some())
.map(|&x| x.unwrap())
.collect();
println!("nums: {:?}", nums);
}
Playground
Which gives the error
error[E0507]: cannot move out of borrowed content
--> src/main.rs:17:15
|
17 | .map(|&x| x.unwrap())
| ^-
| ||
| |hint: to prevent move, use `ref x` or `ref mut x`
| cannot move out of borrowed content
In Rust, when you need a value, you generally want to move the elements or clone them.
Since move is more general, here it is, only two changes are necessary:
let nums: Vec<Uncopyable> = num_opts
.into_iter()
// ^~~~~~~~~~~~-------------- Consume vector, and iterate by value
.filter(|x| x.is_some())
.map(|x| x.unwrap())
// ^~~------------------ Take by value
.collect();
As llogiq points out, filter_map is specialized to filter out None already:
let nums: Vec<Uncopyable> = num_opts
.into_iter()
// ^~~~~~~~~~~~-------- Consume vector, and iterate by value
.filter_map(|x| x)
// ^~~----- Take by value
.collect();
And then it works (consuming num_opts).
As pointed out by #nirvana-msu, in Rust 1.33 std::convert::identity was added which can be used instead of |x| x. From the documentation:
let filtered = iter.filter_map(identity).collect::<Vec<_>>();
You don't need to copy the Uncopyable at all, if you are OK with using a Vec of references into the original Vec:
let nums: Vec<&Uncopyable> = num_opts.iter().filter_map(|x| x.as_ref()).collect();
// ^ notice the & before Uncopyable?
This may not do the trick for you if you have to work with an API that requires &[Uncopyable]. In that case, use Matthieu M.'s solution which can be reduced to:
let nums: Vec<Uncopyable> = num_opts.into_iter().filter_map(|x| x).collect();

Conflicting lifetime requirement for iterator returned from function

This may be a duplicate. I don't know. I couldn't understand the other answers well enough to know that. :)
Rust version: rustc 1.0.0-nightly (b47aebe3f 2015-02-26) (built 2015-02-27)
Basically, I'm passing a bool to this function that's supposed to build an iterator that filters one way for true and another way for false. Then it kind of craps itself because it doesn't know how to keep that boolean value handy, I guess. I don't know. There are actually multiple lifetime problems here, which is discouraging because this is a really common pattern for me, since I come from a .NET background.
fn main() {
for n in values(true) {
println!("{}", n);
}
}
fn values(even: bool) -> Box<Iterator<Item=usize>> {
Box::new([3usize, 4, 2, 1].iter()
.map(|n| n * 2)
.filter(|n| if even {
n % 2 == 0
} else {
true
}))
}
Is there a way to make this work?
You have two conflicting issues, so let break down a few representative pieces:
[3usize, 4, 2, 1].iter()
.map(|n| n * 2)
.filter(|n| n % 2 == 0))
Here, we create an array in the stack frame of the method, then get an iterator to it. Since we aren't allowed to consume the array, the iterator item is &usize. We then map from the &usize to a usize. Then we filter against a &usize - we aren't allowed to consume the filtered item, otherwise the iterator wouldn't have it to return!
The problem here is that we are ultimately rooted to the stack frame of the function. We can't return this iterator, because the array won't exist after the call returns!
To work around this for now, let's just make it static. Now we can focus on the issue with even.
filter takes a closure. Closures capture any variable used that isn't provided as an argument to the closure. By default, these variables are captured by reference. However, even is again a variable located on the stack frame. This time however, we can give it to the closure by using the move keyword. Here's everything put together:
fn main() {
for n in values(true) {
println!("{}", n);
}
}
static ITEMS: [usize; 4] = [3, 4, 2, 1];
fn values(even: bool) -> Box<Iterator<Item=usize>> {
Box::new(ITEMS.iter()
.map(|n| n * 2)
.filter(move |n| if even {
n % 2 == 0
} else {
true
}))
}