When sorting with multiple keys, how can I reverse the order of an individual key? For example:
vec.sort_by_key(|k| (foo(k).reverse(), bar(k)));
You can use sort_by paired with Ordering::reverse instead of sort_by_key.
use std::cmp::Ordering;
#[derive(Debug)]
struct Foo(&'static str, u8);
impl Foo {
fn name(&self) -> &str { self.0 }
fn len(&self) -> u8 { self.1 }
}
fn main() {
let mut vec = vec![Foo("alpha", 1), Foo("beta", 2), Foo("beta", 1)];
vec.sort_by(|a, b| {
match a.name().cmp(b.name()).reverse() {
Ordering::Equal => a.len().cmp(&b.len()),
other => other,
}
});
println!("{:?}", vec);
}
This sorts in reverse alphabetical order, then ties are sorted in ascending numerical order:
[Foo("beta", 1), Foo("beta", 2), Foo("alpha", 1)]
Since Rust 1.17 (via RFC 1677), you can write it like this:
vec.sort_by(|a, b| {
a.name().cmp(b.name()).reverse()
.then(a.len().cmp(&b.len()))
});
If you have something that can naturally be negated / inverted, you can simply negate the key.
Since Rust 1.19, the std::cmp::Reverse struct wraps a value and implements PartialOrd and Ord by calling partial_cmp and cmp with swapped arguments in order to return the reversed order. Just wrap the key to sort in descending order:
vec.sort_by_key(|k| (Reverse(foo(k)), bar(k)));
Before Rust 1.19, you can use the revord crate (documentation) which provides the struct RevOrd which provides the same benefit::
vec.sort_by_key(|k| (RevOrd(foo(k)), bar(k)));
Here's a similar approach to the problem: create a function for chaining multiple orderings:
/// chain two orderings: the first one gets more priority
fn chain_ordering(o1: Ordering, o2: Ordering) -> Ordering {
match o1 {
Ordering::Equal => o2,
_ => o1,
}
}
Then use sort_by, possibly with pattern matching, to produce the ordering of each key:
#[derive(Debug, PartialEq)]
struct HeroSkill(&'static str, &'static str);
fn main() {
// a vector of hero names and super powers
let mut v = vec![
HeroSkill("Bob", "X"),
HeroSkill("Bob", "Y"),
HeroSkill("Alice", "X")
];
// sort by name, then by super power, where Y is more powerful than X
v.sort_by(|&HeroSkill(name1, power1), &HeroSkill(name2, power2)| {
chain_ordering(name1.cmp(name2), power1.cmp(power2).reverse())
});
assert_eq!(v, vec![
HeroSkill("Alice", "X"),
HeroSkill("Bob", "Y"),
HeroSkill("Bob", "X")
]);
}
Playground
Related
I want to modify a collection in place before returning it:
fn main() {
println!("{:?}", compute()); // should print [[2, 1, 0], [5, 4, 3]]
}
// u8 is just a placeholder, so impl Copy is considered cheating :)
fn compute() -> Vec<Vec<u8>> {
let a = vec![0, 1, 2];
let b = vec![3, 4, 5];
let mut result = Vec::new();
result.push(a);
result.push(b);
// avoids allocations from:
//
// result.iter()
// .map(|r| {
// r.reverse()
// r
// })
// .collect::<Vec<_>>()
result.into_iter().for_each(|mut r| r.reverse());
// errors out: the collection was consumed the line above
result
}
A collection was already allocated with Vec::new(), so allocating a second collection here seems like a waste. I am assuming that's what .collect() does.
How do I avoid the allocation in excess?
Is there any easy way to know how many allocations are happening? In golang it was as easy as go test -bench=., but I can't find anything similar when it comes to Rust.
Link to playground
You need to use a &mut to each of the inside vectors, for that you can just use iter_mut which uses &mut Self instead of Self for the outer vector.
// u8 is just a placeholder, so impl Copy is considered cheating :)
fn compute() -> Vec<Vec<u8>> {
let a = vec![0, 1, 2];
let b = vec![3, 4, 5];
let mut result = Vec::new();
result.push(a);
result.push(b);
result.iter_mut().for_each(|r| r.reverse());
result
}
Playground
An example from the documentation about vectors:
let v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2];
println!("The third element is {}", third);
match v.get(2) {
Some(third) => println!("The third element is {}", third),
None => println!("There is no third element."),
}
I can't see why third needs to be a reference. let third: i32 = v[2] seems to work just as well. What does making it a reference achieve?
Similarly:
let v = vec![100, 32, 57];
for i in &v {
println!("{}", i);
}
why is it in &v instead of just in v?
let third: i32 = v[2] works because i32 implements Copy trait. They don't get moved out when indexing the vector, they get copied instead.
When you have a vector of non Copy type, it is a different story.
let v = vec![
"1".to_string(),
"2".to_string(),
"3".to_string(),
"4".to_string(),
"5".to_string(),
];
let third = &v[2]; // This works
// let third = v[2]; // This doesn't work because String doesn't implement Copy
As for the second question about the loop, for loop is syntactic sugar for IntoIterator which moves and consumes.
So, when you need to use v after the loop, you don’t want to move it. You want to borrow it with &v or v.iter() instead.
let v = vec![100, 32, 57];
for i in &v { // borrow, not move
println!("{}", i);
}
println!("{}", v[0]); // if v is moved above, this doesn't work
Context
An object is moving in one direction: Up, Right, Down, or Left.
The next direction will be chosen randomly.
The next possible direction cannot be backwards.
Example
If it is going Right, it could go Up, Right or Down, but not Left.
Enum
There is a simple enum for directions:
#[derive(Debug, PartialEq)]
enum Direction {
Up,
Right,
Down,
Left,
}
Function signature
I would say that this is the function signature that accomplishes the task:
fn next_direction(current_dir: Direction) -> Direction
Current implementation
This is my current implementation:
use rand::prelude::*;
fn next_direction(current_dir: Direction) -> Direction {
let mut rng = thread_rng();
// Possible next direction
let next_dir_iter = [
Direction::Up,
Direction::Down,
Direction::Left,
Direction::Right,
]
.iter()
.filter(|&dir| match (current_dir, dir) {
(Direction::Up, Direction::Down) => false,
(Direction::Down, Direction::Up) => false,
(Direction::Left, Direction::Right) => false,
(Direction::Right, Direction::Left) => false,
(_, _) => true,
});
// Choose one
let dir = next_dir_iter.choose(&mut rng).unwrap();
// Return Direction instead of &Direction
match dir {
Direction::Up => Direction::Up,
Direction::Down => Direction::Down,
Direction::Left => Direction::Left,
Direction::Right => Direction::Right,
}
}
Could this function be written in a clearer, simpler, more efficient way?
I would say that readability is a plus, so a one liner or code golf implementation could not be optimal.
I have found How do I choose a random value from an enum?
You can write the possible directions for each case by hand:
use rand::prelude::*;
use Direction::*;
#[derive(Debug, PartialEq, Copy, Clone)]
enum Direction {
Up,
Right,
Down,
Left,
}
impl Direction {
fn next_random(self) -> Self {
match self {
Up => [Up, Left, Right],
Down => [Down, Left, Right],
Left => [Up, Down, Left],
Right => [Up, Down, Right],
}
.choose(&mut thread_rng())
.copied()
.unwrap()
}
}
Of course, if your enum has a lot of variants, it's better to have a more generic solution:
impl Direction {
fn all() -> &'static [Self] {
&[Up, Down, Left, Right]
}
fn opposite(self) -> Self {
match self {
Up => Down,
Down => Up,
Left => Right,
Right => Left,
}
}
fn next_random(self) -> Self {
let next = Self::all()
.iter()
.filter(|&&d| d != self.opposite())
.choose(&mut thread_rng());
*next.unwrap()
}
}
Note that if you want better performances or flexibility, you may pass the random number generator as a parameter:
fn next_random(self, rng: &mut impl Rng) -> Self {
let next = Self::all()
.iter()
.filter(|&&d| d != self.opposite())
.choose(rng);
*next.unwrap()
}
I have enums that contain variables:
enum Asymmetric {
One(i32),
Two(i32, i32),
}
I want to change just one field of an already existing enum, without reassigning the entire enum. My code (playground):
// Does not compile
fn main() {
let two = Asymmetric::Two(4, 5);
let mut vec = vec![two];
foo(&mut vec[0]);
}
fn foo(baa: &mut Asymmetric) {
match baa {
&mut Asymmetric::Two(x0, x1) => {
x0 = 6;
}
_ => {}
}
}
This results in this error:
error[E0384]: re-assignment of immutable variable `x0`
--> src/main.rs:16:13
|
15 | &mut Asymmetric::Two(x0, x1) => {
| -- first assignment to `x0`
16 | x0 = 6;
| ^^^^^^ re-assignment of immutable variable
Thanks to "match ergonomics" (introduced in Rust 1.26, proposed here), you can write your code like this:
fn foo(baa: &mut Asymmetric) {
match baa {
Asymmetric::Two(x0, _) => {
*x0 = 6;
}
_ => {}
}
}
Since baa is a mutable reference, but your pattern you're matching against (Asymmetric::Two(x0, _)) is not, the name x0 is automatically bound as mutable reference.
You can also do it manually by using ref mut. See this working code (playground):
fn foo(baa: &mut Asymmetric) {
match *baa {
Asymmetric::Two(ref mut x0, _) => {
*x0 = 6;
}
_ => {}
}
}
Some minor changes that are not related to your error, but which increase your code quality:
usually you deref (with *) the matched-on value instead of adding & or &mut to every pattern in the match
you should use _ as a name placeholder if you don't need to bind to that name
In your case, you can simplify the code even further by using if let. Whenever you are only interested in one match-case, you should use if let instead:
fn foo(baa: &mut Asymmetric) {
if let Asymmetric::Two(x0, _) = baa {
*x0 = 6;
}
}
I'm coming from a C (and to a lesser extent, C++) background. I wrote the following code snippet:
fn main() {
let my_array = [1, 2, 3];
let print_me = |j| println!("= {}", j);
for k in my_array.iter() {
print_me(k);
}
}
This compiled and ran as expected, but then I specified the type of the argument passed to the closure print_me thus:
fn main() {
let my_array = [1, 2, 3];
let print_me = |j: i32| println!("= {}", j);
for k in my_array.iter() {
print_me(k);
}
}
I got a compilation error:
error[E0308]: mismatched types
--> src/main.rs:6:22
|
6 | print_me(k);
| ^
| |
| expected i32, found &{integer}
| help: consider dereferencing the borrow: `*k`
|
= note: expected type `i32`
found type `&{integer}`
Now this confused me until I changed k to &k in the for statement, which worked fine:
fn main() {
let my_array = [1, 2, 3];
let print_me = |j: i32| println!("= {}", j);
for &k in my_array.iter() {
print_me(k);
}
}
It seems that I misunderstood the for syntax itself -- or maybe the exact workings of an iterator -- or maybe the usage syntax of a reference vis-a-vis a pointer [which are related but distinct in C++].
In the construct for A in B { C1; C2; ... Cn }, what exactly are A and B supposed to be?
First of all, here's a link to the definition of for in the reference.
To summarise, B is any expression which evaluates to something that can be converted into a value that implements the Iterator<T> trait, whilst A is a irrefutable pattern that binds values of type T.
In your specific case, slice::iter returns an Iter<i32>, which implements Iterator<Item = &i32>. That is, it doesn't yield i32s, it yields &i32s.
Thus, in both the first and second examples, k is actually binding to &i32s, not i32s. When you specified the type of the closure, you were actually specifying the wrong type. The reason the final example works is because A is a pattern, not a variable name. What &k is actually doing is "de-structuring" the &i32, binding the i32 part to a variable named k.
The "irrefutable" part simply means that the pattern must always work. For example, you can't do for Some(x) in thingy where thingy implements Iterator<Option<_>>; Some(x) would not necessarily be valid for every element in the iterator; thus, it's a refutable pattern.
Many iterators actually return a reference rather than a value. To be sure, you have to check the return type of .iter(), which should be of the form Iterator<Item = X>: X will be the type of the variable returned.
So here:
fn main() {
let my_array = [1, 2, 3];
let print_me = |j: i32| println!("= {}", j);
for k in my_array.iter() {
print_me(k);
}
}
This X is &i32 (a reference to i32), and therefore k has type &i32.
This is why, when calling print_me, there is an error: &i32 is passed where i32 is expected.
There are multiple possible fixes here:
specify a different type to print_me:
let print_me = |j: &i32| println!("= {}", j);
dereference the value of k:
print_me(*k);
change the type of k by destructuring in the loop:
for &k in my_array.iter() { ... }
The destructuring occurs because for .. in accepts an irrefutable pattern, so you can pattern match like you would do in a match expression, except that the variable's type has to match (otherwise you get a compiler time error).
To better illustrate it, we can use a slightly more complicated example:
fn main() {
let my_array = [(1, 2), (2, 3), (3, 4)];
let print_me = |a: i32, b: i32| println!("= {} {}", a, b);
for &(j, k) in my_array.iter() {
print_me(j, k)
}
}
The type of my_array is [(i32, i32)]: an array of tuples of 2 i32. The result of .iter() is therefore of type Iterator<Item = &(i32, i32)>: an iterator to a reference to a tuple of 2 i32 aka &(i32, i32).
When we use the irrefutable pattern &(j, k) what happens is that we destructure the tuple so that:
the first element binds to j (inferred to be of type i32, only works because i32 is Copy)
the second element binds to k ((inferred to be of type i32)
j and k thus become temporary copies of the i32 inside this element.