I feel like this code should work:
use ndarray::{Array1, s}; // 0.15.4
fn main() {
let x = Array1::<f64>::range(0.0, 10.0, 1.0);
println!("{:?}", x);
println!("{:?}", x.slice(s![1..]));
println!("{:?}", x.slice(s![..-1]));
println!("{:?}", x.slice(s![1..]) - x.slice(s![..-1])); // fails to compile when this line is uncommented
}
The first 3 print lines do work if I comment the final print. Am I missing something here?
Rust Playground Implementation
The documentation explains that:
Let A be an array or view of any kind. Let B be an array with owned
storage (either Array or ArcArray). Let C be an array with mutable
data (either Array, ArcArray or ArrayViewMut). The following
combinations of operands are supported for an arbitrary binary
operator denoted by # (it can be +, -, *, / and so on).
&A # &A which produces a new Array
B # A which consumes B, updates it with the result, and returns it
B # &A which consumes B, updates it with the result, and returns it
C #= &A which performs an arithmetic operation in place
And also:
You can use slicing to create a view of a subset of the data in the
array. Slicing methods include .slice(), .slice_mut(), .slice_move(),
and .slice_collapse().
So you want to use &x.slice(s![1..]) - &x.slice(s![..-1]) (note the two &).
Related
I am trying to flatten a vector of Enum in Rust, but I am having some issues:
enum Foo {
A(i32),
B(i32, i32),
}
fn main() {
let vf = vec![Foo::A(1), Foo::A(2), Foo::B(3, 4)];
let vi: Vec<i32> = vf
.iter()
.map(|f| match f {
Foo::A(i) => [i].into_iter(),
Foo::B(i, j) => [i, j].into_iter(),
})
.collect(); // this does not compile
// I want vi = [1, 2, 3, 4]. vf must still be valid
}
I could just use a regular for loop and insert elements into an existing vector, but that would be no fun. I'd like to know if there is a more idiomatic Rust way of doing it.
Here's a way to do it that produces an iterator (rather than necessarily a vector, as the fold() based solution does).
use std::iter::once;
enum Foo {
A(i32),
B(i32, i32),
}
fn main() {
let vf = vec![Foo::A(1), Foo::A(2), Foo::B(3, 4)];
let vi: Vec<i32> = vf
.iter()
.flat_map(|f| {
match f {
&Foo::A(i) => once(i).chain(None),
&Foo::B(i, j) => once(i).chain(Some(j)),
}
})
.collect();
dbg!(vi);
}
This does essentially the same thing that you were attempting, but in a way which will succeed. Here are the parts I changed, in the order they appear in the code:
I used .flat_map() instead of .map(). flat_map accepts a function which returns an iterator and produces the elements of that iterator ("flattening") whereas .map() would have just given the iterator.
I used & in the match patterns. This is because, since you are using .iter() on the vector (which is appropriate for your requirement “vf must still be valid”), you have references to enums, and pattern matching on a reference to an enum will normally give you references to its elements, but we almost certainly want to handle the i32s by value instead. There are several other things I could have done, such as using the * dereference operator on the values instead, but this is concise and tidy.
You tried to .into_iter() an array. Unfortunately, in current Rust this does not do what you want and you can't actually return that iterator, for somewhat awkward reasons (which will be fixed in an upcoming Rust version). And then, if it did mean what you wanted, then you'd get an error because the two match arms have unequal types — one is an iterator over [i32; 1] and the other is an iterator over [i32; 2].
Instead, you need to build two possible iterators which are clearly of the same type. There are lots of ways to do this, and the way I picked was to use Iterator::chain to combine once(i), an iterator that returns the single element i, with an Option<i32> (which implements IntoIterator) that contains the second element j if it exists.
Notice that in the first match arm I wrote the seemingly useless expression .chain(None); this is so that the two arms have the same type. Another way to write the same thing, which is arguably clearer since it doesn't duplicate code that has to be identical, is:
let (i, opt_j) = match f {
&Foo::A(i) => (i, None),
&Foo::B(i, j) => (i, Some(j)),
};
once(i).chain(opt_j)
In either case, the iterator's type is std::iter::Chain<std::iter::Once<i32>, std::option::IntoIter<i32>> — you don't need to know this exactly, just notice that there must be a type which handles both the A(i) and the B(i, j) cases.
First of all, you need to change the i32 references to owned values by e.g. dereferencing them. Then you can circumvent proxying through inlined arrays by using fold():
enum Foo {
A(i32),
B(i32, i32),
}
fn main() {
let vf = vec![Foo::A(1), Foo::A(2), Foo::B(3, 4)];
let vi: Vec<i32> = vf
.iter()
.fold(Vec::new(), |mut acc, f| {
match f {
Foo::A(i) => acc.push(*i),
Foo::B(i, j) => {
acc.push(*i);
acc.push(*j);
}
}
acc
});
}
I have a vector of numbers and use the windows(2) method to create an iterator that gives me neighbouring pairs. For example, the vector [1, 2, 3] is transformed into [1, 2], [2, 3]. I want to use the find method to find a slice that fulfills a specific condition:
fn step(g: u64) -> Option<(u64, u64)> {
let prime_list: Vec<u64> = vec![2, 3, 5, 7]; //For example
if prime_list.len() < 2 {
return None;
}
let res = prime_list.windows(2).find(|&&[a, b]| b - a == g)?;
//...
None
}
I get an error:
error[E0005]: refutable pattern in function argument: `&&[]` not covered
--> src/lib.rs:6:43
|
6 | let res = prime_list.windows(2).find(|&&[a, b]| b - a == g)?;
| ^^^^^^^^ pattern `&&[]` not covered
I don't know what that error means: the list cannot have less than two elements, for example. Maybe the closure parameter is wrong? I tried to vary it but that didn't change anything. a and b are being properly detected as u64 in my IDE too. What is going on here?
You, the programmer, know that each iterated value will have a length of 2, but how do you know that? You can only tell that from the prose documentation of the function:
Returns an iterator over all contiguous windows of length size. The windows overlap. If the slice is shorter than size, the iterator returns no values.
Nowhere does the compiler know this information. The implementation of Windows only states that the iterated value will be a slice:
impl<'a, T> Iterator for Windows<'a, T> {
type Item = &'a [T];
}
I'd convert the slice into an array reference, discarding any slices that were the wrong length (which you know cannot happen):
use std::convert::TryFrom;
fn step(g: u64) -> Option<(u64, u64)> {
let prime_list: Vec<u64> = vec![2, 3, 5, 7]; // For example
if prime_list.len() < 2 {
return None;
}
let res = prime_list
.windows(2)
.flat_map(<&[u64; 2]>::try_from)
.find(|&&[a, b]| b - a == g)?;
//...
None
}
See also:
How to convert a slice into an array reference?
How can I find a subsequence in a &[u8] slice?
How do I imply the type of the value when there are no type parameters or ascriptions?
Alternatively, you could use an iterator of integers and chunk it up.
See also:
Are there equivalents to slice::chunks/windows for iterators to loop over pairs, triplets etc?
At some point in the future, const generics might be stabilized and allow baking the array length into the function call and the return type.
See also:
Is it possible to control the size of an array using the type parameter of a generic?
As a Rust newbie, I'm working through the Project Euler problems to help me get a feel for the language. Problem 4 deals with palindromes, and I found two solutions for creating a vector of palindromes, but I'm not sure how either of them work.
I'm using a vector of strings, products, that's calculated like this:
let mut products = Vec::new();
for i in 100..500 {
for j in 500..1000 {
products.push((i * j).to_string());
}
}
For filtering these products to only those that are palindromic, I have the following two solutions:
Solution 1:
let palindromes: Vec<_> = products
.iter()
.filter(|&x| x == &x.chars().rev().collect::<String>())
.collect();
Solution 2:
let palindromes: Vec<_> = products
.iter()
.filter(|&x| *x == *x.chars().rev().collect::<String>())
.collect();
They both yield the correct result, but I have no idea why!
In Solution 1, we're comparing a reference of a string to a reference of a string we've just created?
In Solution 2, we dereference a reference to a string and compare it to a dereferenced new string?
What I would expect to be able to do:
let palindromes: Vec<_> = products
.iter()
.filter(|x| x == x.chars().rev().collect::<String>())
.collect();
I'm hoping somebody will be able to explain to me:
What is the difference is between my two solutions, and why do they both work?
Why can't I just use x without referencing or dereferencing it in my filter function?
Thank you!
Vec<String>.iter() returns an iterator over references (&String).
The closure argument of .filter() takes a reference to an iterator's item. So the type that is passed to the closure is a double reference &&String.
|&x| tells the closure to expect a reference, so x is now of type &String.
First solution: collect returns a String, of which & takes the reference. x is also a reference to a string, so the comparison is between two &String.
Second solution: The dereference operator * is applied to x, which results in a String. The right hand side is interesting: The String result of collect is dereferenced. This results in a string slice because String implements Deref<Target=str>. Now the comparison is between String and str, which is works because it is implemented in the standard library (Note that a == b is equivalent to a.eq(&b)).
Third solution: The compiler explains why it does not work.
the trait std::cmp::PartialEq<std::string::String> is not implemented for &&std::string::String
The left side is a double reference to string (&&String) and the right side is just a String . You need to get both sides to the same "reference level". All of these work:
x.iter().filter(|x| x == &&x.chars().rev().collect::<String>());
x.iter().filter(|x| *x == &x.chars().rev().collect::<String>());
x.iter().filter(|x| **x == x.chars().rev().collect::<String>());
Let's say I have vectors of primes and powers:
let mut primes: Vec<usize> = ...;
let mut powers: Vec<u32> = ...;
It is a fact that primes.len() == powers.len().
I'd like to return to the user a list of primes which have a corresponding power value of 0 (this code is missing proper refs and derefs):
primes.iter().zip(powers)
.filter(|(p, power)| power > 0)
.map(|(p, power)| p)
.collect::<Vec<usize>>()
The compiler is complaining a lot, as you might imagine. In particular, the filter is receiving arguments of type &(&usize, &u32), but I am not correctly de-referencing in the pattern matching. I have tried various patterns the compiler suggests (e.g. &(&p, &power), which is the one that makes the most sense to me), but with no luck. How do I correctly perform the pattern matching so that I can do the power > 0 comparison without issue, and so that I can collect in the end a Vec<usize>?
primes.iter().zip(powers)
iter() iterates by reference, so you get &usize elements for primes. OTOH .zip() calls .into_iter() which iterates owned values, so powers are u32, and these iterators combined iterate over (&usize, u32). Technically, there's nothing wrong with iterating over such mixed type, but the inconsistency may be confusing. You can use .into_iter() or .iter().cloned() on primes to avoid the reference, or call .zip(powers.iter()) to get both as references.
Second thing is that .filter() takes items by reference &(_,_) (since it only "looks" at them), and .map() by owned value (_,_) (which allows it to change and return it).
For small values like integers, you'd usually use these methods like this:
.filter(|&item| …)
.map(|item| …)
Note that in closures the syntax is |pattern: type|, so in the example above &item is equivalent to:
.filter(|by_ref| {
let item = *by_ref;
})
That works:
fn main() {
let primes: Vec<usize> = vec![2, 3, 5, 7];
let powers: Vec<u32> = vec![2, 2, 2, 2];
let ret = primes.iter().zip(powers.iter())
.filter_map(|(p, pow)| { // both are refs, so we need to deref
if *pow > 0 {
Some(*p)
} else {
None
}
})
.collect::<Vec<usize>>();
println!("{:?}", ret);
}
Note that I also used powers.iter() which yields elements by reference. You could also use cloned() on both iterators and work with values.
filter_map can be used well with match:
.filter_map(|(p, pow)| match pow.cmp(&0) {
Greater => Some(*p),
_ => None,
})
Playground
In pseudo-code, I'm trying the following:
for i in len(array):
try:
a = array[i-1]
except(out_of_bounds_error):
a = false
where array is just made up of booleans.
In the book (Chapter 9.2) it says you can check whether a function returns a result or not with something like:
let a: u32 = array[i-1]
which tells me a is indeed a bool. Without a Result type, how do I handle the inevitable (and expected) attempt to subtract with overflow error at runtime?
The error attempt to subtract with overflow occurs when computing i - 1 when i == 0. Array indices must be of type usize, which is an unsigned type, and unsigned types cannot represent negative numbers, which 0 - 1 would produce. In a debug build, the compiler generates code that raises this error, but in a release build, the compiler generates code that will simply compute the "wrong" value (in this case, this happens to be usize::max_value()).
You can avoid this error in both debug builds and release builds by performing a checked subtraction instead. checked_sub returns an Option: you'll get a Some if the subtraction succeeded or None if it failed. You can then use map_or on that Option to read the array only if the subtraction produced a valid index.
fn main() {
let a = vec![true; 10];
for i in 0..a.len() {
let b = i.checked_sub(1).map_or(false, |j| a[j]);
println!("b: {}", b);
}
}
Arrays (or rather, slices) also have a get method that returns an Option if the index is out of bounds, instead of panicking. If we were adding one to the index, instead of subtracting one, we could do this:
fn main() {
let a = vec![true; 10];
for i in 0..a.len() {
let b = i.checked_add(1).and_then(|j| a.get(j).cloned()).unwrap_or(false);
println!("b: {}", b);
}
}
This time, we're using and_then to chain an operation that produces an Option with another operation that also produces an Option, and we're using unwrap_or to get the Option's value or a default value if it's None.