The only real difference I can figure out after reading the beginner guide, is that in tuple you can have values of multiple types? Both are immutable?
And what are the use cases where I'd want a tuple or array, apart from the obvious one.
An array is a list of items of homogeneous type. You can iterate over it and index or slice it with dynamic indices. It should be used for homegeneous collections of items that play the same role in the code. In general, you will iterate over an array at least once in your code.
A tuple is a fixed-length agglomeration of heterogeneous items. It should be thought of as a struct with anonymous fields. The fields generally have different meaning in the code, and you can't iterate over it.
Array
collection of values of the same type
fixed-sized collection
Accessing element
You can access element of array by array's name, square brackets, and index, ex:
let arr = [22, 433, 55];
assert_eq!(arr[0], 22);
Destructuring arrays
Arrays can be destructured into multiple variables, ex:
let arr = [1, 42 ,309];
let [id, code, set] = arr;
assert_eq!(id, 1);
assert_eq!(code, 42);
assert_eq!(set, 309);
Tuple
collection of values of different types
finite heterogeneous sequence
Accessing element
You can access element of tuple by tuple's name, dot, and index, ex:
let tup = (22, "str", 55);
assert_eq!(tup.0, 22);
Functions
Tuples may be used to return multiple values from functions, ex:
fn num(i: u32) -> (i64, u32) {
(-33, 33 + i)
}
assert_eq!(num(12), (-33, 45));
Destructuring tuples
Tuples can also be destructured and it's more common practise to destructure tuples rather than arrays, ex:
let tup = (212, "Wow", 55);
let (num, word, id) = tup;
assert_eq!(num, 212);
assert_eq!(word, "Wow");
assert_eq!(id, 55);
Useful resources:
Compound Types - The Rust Programming Language
Tuples - Rust by example
Arrays and Slices - Rust by example
Tuples:
Items can be heterogenous types
Fixed number of items
Indexing via . syntax e.g myTuple.0 for first element
Mutable only with mut keyword
Arrays:
Item are same type
Fixed number of items
Indexing via [] syntax e.g myArr.[0] for first element
Mutable only with mut keyword
Example:
For the example I have declared the types explicitly so you can the what types the variables are. In your code you can leave them out
usually since the compiler will infer them.
fn main() {
let mut tupleA: (i32, i32, &str) = (3434, 5634, "abc");
let tupleB: (char, i32, bool) = ('d', 456, false);
let mut arrayA: [i32; 3] = [1,2,3];
let arrayB: [bool; 4] = [false, true, false, true];
tupleA.1 = 5;
arrayA[0] = 5;
println!("{:?} {:?} {:?} {:?}", tupleA, tupleB, arrayA, arrayB)
// prints (3434, 5, "abc") ('d', 456, false) [5, 2, 3] [false, true, false, true]
}
Related
I want to iterate over a tuple using a loop, like in Python. Is it possible in Rust?
let tup1 = (1, '2', 3.0);
for i in tup1.iter() {
println!("{}", i);
}
The type of each element of a tuple can be different, so you can't iterate over them. Tuples are not even guaranteed to store their data in the same order as the type definition, so they wouldn't be good candidates for efficient iteration, even if you were to implement Iterator for them yourself.
However, an array is exactly equivalent to a tuple, with all elements of the same type:
let tup = [1, 2, 3];
for i in tup.iter() {
println!("{}", i);
}
See also:
How to iterate or map over tuples?
Why does the 2-tuple Functor instance only apply the function to the second element?
You can combine the tuple into an array.
const brackets: &[(&str, &str)] = &[("(", ")"), ("[", "]"), ("{", "}")];
for b in brackets.iter() {
for c in [b.0, b.1].iter() {
println!("{}", c);
}
}
So technically a way to go is:
for element in [tuple.0, tuple.1, ...].iter() { ... }
I have a vector like [1, 2, 4, 3], I want to remove 3 because 3 is smaller than 4.
I want to use the iterator to solve this problem, and do not use the loop or for_each.
The first step I think need to do is vec.into_iter, but I don't know what to do next.
To reformulate, you want to remove any element smaller than the previous element.
Let's write a function to do so. As you want to work exclusively with iterators, therefore in a functional style, we are going to assume the input vector is immutable, so the function should take a slice as input, and return a new Vec:
fn remove_smaller<T: Ord + Copy>(v: &[T]) -> Vec<T> {
v.iter()
.rev()
.collect::<Vec<_>>()
.windows(2)
.filter(|a| a[0] > a[1])
.map(|a| *a[0])
.chain([v[0]])
.rev()
.collect()
}
Let's explain what this function is doing, using vec![1, 2, 4, 3] as sample input.
We first reverse the order of the vector so we can operate on windows looking at the previous value, and collect it into a new vector (needed as windows is implemented for slices only).
&[3, 4, 2, 1]
windows(2) returns an iterator that will yield overlapping pairs of elements of the slice, except the last element, which has no next:
&[3, 4], &[4, 2], &[2, 1]
We then filter with filter(|a| a[0] > a[1]) meaning we only keep entries which are ordered (hence why type of input needs to be Ord):
&[4, 2], &[2, 1]
We then map with map(|a| *a[0]) in order to keep each value, which needs T to be Copy:
4, 2
Now, since we are missing the first element of the input array, we need to add it again, using .chain([v[0]]) giving us:
4, 2, 1
We then reverse the iterator to obtain the output array in correct order:
1, 2, 4
See it in action in the playground.
This is not a very efficient method to achieve the result, as it needs to allocate twice as much memory as the input.
You can use the zip and skip functionality to put together two elements of an array.
Following the footsteps of #sirdarius, Here is how your function can be:
fn remove_smaller<T: Ord + Copy>(v: &[T]) -> Vec<T> {
let mut res = vec![v[0]];
res.extend(
v.iter()
.zip(v.iter().skip(1))
.filter(|(a, b)| a < b)
.map(|(_, b)| *b),
);
res
}
Walk through:
We fist create our result vector and push the first element in it since it is always in the answer vector.
Then we extend our result vector by another iterator which would perform the following:
create a tuple for each element of the array with indices of the same array but one index ahead (v.iter().skip(1)).
we then filter out pairs which meet our ordering and finally, we map the pair to a single value.
There is an iterator only way to do what you wanted in O(1) space.
fn non_decreasing(v: Vec<i32>) -> Vec<i32> {
if v.is_empty() {
return v;
}
let first = v[0];
once(first)
.chain(
v.into_iter()
.skip(1)
.scan(first, |last_max, cur_elem| {
if cur_elem < *last_max {
Some(None)
} else {
*last_max = cur_elem;
Some(Some(cur_elem))
}
})
.flatten(),
)
.collect()
}
This function will not use any extra space (even for the output, on newer rustc versions). It will return a vector that's non-decreasing. That is, each element in the result vector will be >= the previous one.
If you wanted to compare the elements only to the previous element and not the previous largest, then just add the *last_max = cur_elem line to the if branch as well.
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?
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
What's the best way to compare 2 vectors or strings element by element in Rust, while being able to do processing on each pair of elements? For example if you wanted to keep count of the number of differing elements. This is what I'm using:
let mut diff_count: i32 = 0i32;
for (x, y) in a.chars().zip(b.chars()) {
if x != y {
diff_count += 1i32;
}
}
Is that the correct way or is there something more canonical?
To get the count of matching elements, I'd probably use filter and count.
fn main() {
let a = "Hello";
let b = "World";
let matching = a.chars().zip(b.chars()).filter(|&(a, b)| a == b).count();
println!("{}", matching);
let a = [1, 2, 3, 4, 5];
let b = [1, 1, 3, 3, 5];
let matching = a.iter().zip(&b).filter(|&(a, b)| a == b).count();
println!("{}", matching);
}
Iterator::zip takes two iterators and produces another iterator of the tuple of each iterator's values.
Iterator::filter takes a reference to the iterator's value and discards any value where the predicate closure returns false. This performs the comparison.
Iterator::count counts the number of elements in the iterator.
Note that Iterator::zip stops iterating when one iterator is exhausted. If you need different behavior, you may also be interested in
Itertools::zip_longest or Itertools::zip_eq.
If you wanted to use #Shepmaster's answer as the basis of an assertion to be used in a unit test, try this:
fn do_vecs_match<T: PartialEq>(a: &Vec<T>, b: &Vec<T>) -> bool {
let matching = a.iter().zip(b.iter()).filter(|&(a, b)| a == b).count();
matching == a.len() && matching == b.len()
}
Of course, be careful when using this on floats! Those pesky NaNs won't compare, and you might want to use a tolerance for comparing the other values. And you might want to make it fancy by telling the index of the first nonmatching value.