I would like to walk through a Vec and combine some elements of it. How do I do that in idiomatic Rust?
Example:
#[derive(PartialEq, Debug)]
enum Thing { A, B, AandB }
fn combine(v: Vec<Thing>) -> Vec<Thing> {
// idiomatic code here
}
fn main() {
let v = vec![Thing::A, Thing::B];
assert_eq!(vec![Thing::AandB], combine(v));
}
How I would do it:
Traverse the Vec with Iterator::scan and replace all occurrences of Thing::B with Thing::AandB if Thing::A was the element before. Then I would traverse it again and remove all Thing::As before Thing::AandB.
This seems super complicated and inelegant.
I merged swizard's answer and Shepmaster's answer and ended up with an in-place solution that runs through the vector recursively, has only the vector as a mutable and never moves anything twice. No guarantees on runtime or idiomaticity ;)
use Thing::*;
use std::cmp::min;
#[derive(Copy,Clone,PartialEq,Debug)]
enum Thing { A, B, AandB}
fn combine(mut v: Vec<Thing>) -> Vec<Thing> {
fn inner(res: &mut Vec<Thing>, i: usize, backshift: usize) {
match &res[i..min(i+2, res.len())] {
[A, B] => {
res[i - backshift] = AandB;
inner(res, i + 2, backshift + 1);
},
[a, ..] => {
res[i - backshift] = a;
inner(res, i + 1, backshift);
},
[] => res.truncate(i - backshift),
}
};
inner(&mut v, 0, 0);
v
}
fn main() {
let v = vec![A, A, B, AandB, B, A, B, A, B];
assert_eq!(vec![A, AandB, AandB, B, AandB, AandB], combine(v));
let v = vec![A, A, B, AandB, B, A, B, A, A];
assert_eq!(vec![A, AandB, AandB, B, AandB, A, A], combine(v));
}
Not sure if this counts as idiomatic, but the itertools library has the batching() function for all iterators. Combined with peek() from the standard library, you get your result in one iteration instead of two.
extern crate itertools;
use itertools::Itertools;
use Thing::*;
#[derive(PartialEq, Debug)]
enum Thing { A, B, AandB }
fn combine(v: Vec<Thing>) -> Vec<Thing> {
v.into_iter().peekable().batching(|mut it| {
match it.next() {
Some(A) => {
if Some(&B) == it.peek() {
it.next();
Some(AandB)
} else {
Some(A)
}
}
x => x,
}
}).collect()
}
fn main() {
let v = vec![A, B, A, A, A, B, B, A];
assert_eq!(
vec![AandB, A, A, AandB, B, A],
combine(v)
);
}
obviously collect() will allocate a new buffer.
Here's a solution that uses recursion and pattern-matching. I'm pretty sure the recursion is tail-recursion, and so could be turned into iteration.
use Thing::*;
#[derive(Copy,Clone,PartialEq,Debug)]
enum Thing { A, B, AandB }
fn combine(v: Vec<Thing>) -> Vec<Thing> {
fn inner(mut res: Vec<Thing>, s: &[Thing]) -> Vec<Thing> {
match s {
[A, B, tail..] => {
res.push(AandB);
inner(res, tail)
},
[a, tail..] => {
res.push(a);
inner(res, tail)
},
[] => res,
}
};
inner(Vec::new(), &v)
}
fn main() {
let v = vec![A, A, B, AandB, B, A];
assert_eq!(vec![A, AandB, AandB, B, A], combine(v));
let v = vec![A, A, B, AandB, B, A, B, A, B];
assert_eq!(vec![A, AandB, AandB, B, AandB, AandB], combine(v));
let v = vec![A, A, B, AandB, B, A, B, A, A];
assert_eq!(vec![A, AandB, AandB, B, AandB, A, A], combine(v));
}
I suspect there is no easy way to do that with iterators, but nobody lays embargo on plain old c-style:
#[derive(PartialEq, Debug, Copy)]
enum Thing { A, B, AandB }
fn combine(mut v: Vec<Thing>) -> Vec<Thing> {
let mut prev: Option<Thing> = None;
let mut end = 0;
for i in 0 .. v.len() {
let el = v[i];
match (el, prev) {
(Thing::B, Some(Thing::A)) => {
end = end - 1;
v[end] = Thing::AandB
},
_ =>
v[end] = el
};
prev = Some(el);
end = end + 1;
}
v.truncate(end);
v
}
fn main() {
let v = vec![Thing::A, Thing::A, Thing::B, Thing::AandB, Thing::B, Thing::A];
assert_eq!(vec![Thing::A, Thing::AandB, Thing::AandB, Thing::B, Thing::A], combine(v));
}
Here is one pass with direct transformations.
Okay, here is an idiomatic version then without explicit for-loops and recursion :)
#[derive(PartialEq, Debug, Copy)]
enum Thing { A, B, AandB }
fn combine(mut v: Vec<Thing>) -> Vec<Thing> {
let (_, total) = (0 .. v.len()).fold((None, 0), |&mut: (prev, end), i| {
let el = v[i];
let (next, item) = match (el, prev) {
(Thing::B, Some(Thing::A)) => (end, Thing::AandB),
_ => (end + 1, el),
};
v[next - 1] = item;
(Some(el), next)
});
v.truncate(total);
v
}
fn main() {
let v = vec![Thing::A, Thing::A, Thing::B, Thing::AandB, Thing::B, Thing::A];
assert_eq!(vec![Thing::A, Thing::AandB, Thing::AandB, Thing::B, Thing::A], combine(v));
}
Related
I have this code that does a brute-force search to find a match for a string:
fn main() {
let strings: Vec<String> = ["a", "b", "c","d","e","f","g","h","i","j","K","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"].map(String::from).to_vec();
for i in strings.iter(){
for j in strings.iter(){
for k in strings.iter(){
for l in strings.iter(){
let mut result = format!("{i}{j}{k}{l}");
println!("{}",result);
if result == "Kaio"{
println!("Found it!!");
return ;
}
}
}
}
}
}
Is there a better way to be doing this? Can I do it dynamically? In this example I use four loops, assuming that the final string has a length of four. But what if there's a dynamically-sized string that I don't know the size of?
The itertools crate gives a good macro to generate this in iproduct.
use itertools::iproduct;
fn main() {
let pool: Vec<String> = "abcdefghijklmnopqrstuvwxyz".chars().map(String::from).collect();
let possibilities: Vec<String> = iproduct!(&pool, &pool, &pool, &pool) // for four-letters
.map(|(a, b, c, d)| format!("{}{}{}{}", a, b, c, d))
.collect();
for password in possibilities {
if password == "eggs" {
println!("We found it!");
}
}
}
Pretty new to Rust, decided to brush up using the Advent of Code 2020 Day 1 Puzzle. I'm using the following function:
fn find_numbers_2020(v: Vec<i32>) -> (i32,i32) {
let mut n1: i32 = 0;
let mut n2: i32 = 0;
let mut cnt = 0;
let size = v.len();
for v_i in v {
n1 = v_i;
cnt = cnt+1;
for i in cnt..size {
if (n1 + *v.get(i).unwrap()) == 2020 {
n2 = *v.get(i).unwrap();
(n1, n2) //Issue is here
}
}
}
(n1, n2)
}
But I get the error
"32 (n1, n2)
^^^^^^^^ expected (), found tuple.
It's being called from main as follows
fn main() {
let filename = String::from("./input.txt");
let v = parse_file(filename); //This works fine
for v_i in v {
println!("{}", v_i);
}
let result = find_numbers_2020(v);
let (n1, n2) = result;
println!("{} + {} = {}", n1, n2, n1+n2);
println!("{} * {} = {}", n1, n2, n1*n2);
}
I should also mention that v is a Vec<i32>. Sorry for the beginner question but Rust can be a little confusing and I haven't been able to find any answers through googling.
You can omit the return keyword only if the returned value is the last expression in the function block, otherwise you need to explicitly use return. Adding return to your example fixes that particular error but a bunch of new ones come up in its place. This is how I'd write the function:
fn find_numbers_2020(v: Vec<i32>) -> (i32, i32) {
for (skip, &n1) in v.iter().enumerate() {
for &n2 in v.iter().skip(skip) {
if n1 + n2 == 2020 {
return (n1, n2);
}
}
}
panic!("no pair of numbers in vec sum to 2020");
}
This is one of those cases where you need to use a return expression. Your initial for loop also consumes v, so to be able to do v.get() in the inner loop, you need to borrow v instead, i.e. &v or v.iter().
fn find_numbers_2020(v: Vec<i32>) -> (i32, i32) {
let mut n1: i32 = 0;
let mut n2: i32 = 0;
let mut cnt = 0;
let size = v.len();
for &v_i in &v {
n1 = v_i;
cnt = cnt + 1;
for i in cnt..size {
if (n1 + *v.get(i).unwrap()) == 2020 {
n2 = *v.get(i).unwrap();
return (n1, n2);
}
}
}
(n1, n2)
}
This is also a perfect case of when you could return an Option and use an if let expression. So instead of returning (i32, i32) then you would return Option<(i32, i32)>.
Instead of doing *v.get(i).unwrap(), then you can also just index v, i.e. v[i].
fn find_numbers_2020(v: Vec<i32>) -> Option<(i32, i32)> {
let mut cnt = 0;
for &n1 in &v {
cnt += 1;
for i in cnt..v.len() {
if (n1 + v[i]) == 2020 {
let n2 = v[i];
return Some((n1, n2));
}
}
}
None
}
fn main() {
// ...
if let Some((n1, n2)) = result {
println!("{} + {} = {}", n1, n2, n1 + n2);
println!("{} * {} = {}", n1, n2, n1 * n2);
}
}
Instead of manually incrementing indices, you can use enumerate() in the first loop, then in the second loop you can use skip(i + 1) with the index returned by enumerate().
fn find_numbers_2020(v: Vec<i32>) -> Option<(i32, i32)> {
for (i, &n1) in v.iter().enumerate() {
for &n2 in v.iter().skip(i + 1) {
if (n1 + n2) == 2020 {
return Some((n1, n2));
}
}
}
None
}
Instead of v: Vec<i32>, it would be more idiomatic to use a slice, i.e. v: &[i32]. In main() you just have to borrow v in your find_numbers_2020() call, i.e. find_numbers_2020(&v)
I have go a sample recursive code in go playground, there are 2 "?", the target is to generate all binary strings replacing ? with 0 or 1 , it supposes to display 4 results, but only display 3. ie missing 1100101
package main
import (
"fmt"
//"strings"
//"strconv"
)
func main() {
str := "1?0?101"
mstr := []byte(str)
q := []byte("?")[0]
a := []byte("0")[0]
b := []byte("1")[0]
fmt.Println(mstr)
allstr(mstr, 0, len(mstr), q, a, b)
}
func allstr(mstr []byte, index int, size int, q, a, b byte) {
if index >= size {
fmt.Println(string(mstr))
return
}
if mstr[index] == q {
mstr[index] = a
allstr(mstr, index+1, size, q, a, b)
mstr[index] = b
allstr(mstr, index+1, size, q, a, b)
} else {
allstr(mstr, index+1, size, q, a, b)
}
}
Go playground: https://play.golang.org/p/4e5NIOS9fG4
Output:
[49 63 48 63 49 48 49]
1000101
1001101
1101101
You need to undo the writes to the master byte-slice during recursive-backtracking:
if mstr[index] == q {
mstr[index] = a
allstr(mstr, index+1, size, q, a, b)
mstr[index] = b
allstr(mstr, index+1, size, q, a, b)
mstr[index] = q // <--- add this
}
https://play.golang.org/p/-JEsVGFcsQo
It's quite common to compare data with precedence, for a struct which has multiple members which can be compared, or for a sort_by callback.
// Example of sorting a: Vec<[f64; 2]>, sort first by y, then x,
xy_coords.sort_by(
|co_a, co_b| {
let ord = co_a[1].cmp(&co_b[1]);
if ord != std::cmp::Ordering::Equal {
ord
} else {
co_a[0].cmp(&co_b[0])
}
}
);
Is there a more straightforward way to perform multiple cmp functions, where only the first non-equal result is returned?
perform multiple cmp functions, where only the first non-equal result is returned
That's basically how Ord is defined for tuples. Create a function that converts your type into a tuple and compare those:
fn main() {
let mut xy_coords = vec![[1, 0], [-1, -1], [0, 1]];
fn sort_key(coord: &[i32; 2]) -> (i32, i32) {
(coord[1], coord[0])
}
xy_coords.sort_by(|a, b| {
sort_key(a).cmp(&sort_key(b))
});
}
Since that's common, there's a method just for it:
xy_coords.sort_by_key(sort_key);
It won't help your case, because floating point doesn't implement Ord.
One of many possibilities is to kill the program on NaN:
xy_coords.sort_by(|a, b| {
sort_key(a).partial_cmp(&sort_key(b)).expect("Don't know how to handle NaN")
});
See also
Using max_by_key on a vector of floats
How to do a binary search on a Vec of floats?
There are times when you may not want to create a large tuple to compare values which will be ignored because higher priority values will early-exit the comparison.
Stealing a page from Guava's ComparisonChain, we can make a small builder that allows us to use closures to avoid extra work:
use std::cmp::Ordering;
struct OrdBuilder<T> {
a: T,
b: T,
ordering: Ordering,
}
impl<T> OrdBuilder<T> {
fn new(a: T, b: T) -> OrdBuilder<T> {
OrdBuilder {
a: a,
b: b,
ordering: Ordering::Equal,
}
}
fn compare_with<F, V>(mut self, mut f: F) -> OrdBuilder<T>
where F: for <'a> FnMut(&'a T) -> V,
V: Ord,
{
if self.ordering == Ordering::Equal {
self.ordering = f(&self.a).cmp(&f(&self.b));
}
self
}
fn finish(self) -> Ordering {
self.ordering
}
}
This can be used like
struct Thing {
a: u8,
}
impl Thing {
fn b(&self) -> u8 {
println!("I'm slow!");
42
}
}
fn main() {
let a = Thing { a: 0 };
let b = Thing { a: 1 };
let res = OrdBuilder::new(&a, &b)
.compare_with(|x| x.a)
.compare_with(|x| x.b())
.finish();
println!("{:?}", res);
}
Here's a swap function for two-element tuples:
fn swap<A, B>(obj: (A, B)) -> (B, A)
{
let (a, b) = obj;
(b, a)
}
Example use:
fn main() {
let obj = (10i, 20i);
println!("{}", swap(obj));
}
Is there a way to define swap as a method on two-element tuples? I.e. so that it may be called like:
(10i, 20i).swap()
Yes, there is. Just define a new trait and implement it immediately, something like this:
trait Swap<U> {
fn swap(self) -> U;
}
impl<A, B> Swap<(B, A)> for (A, B) {
#[inline]
fn swap(self) -> (B, A) {
let (a, b) = self;
(b, a)
}
}
fn main() {
let t = (1u, 2u);
println!("{}", t.swap());
}
Note that in order to use this method you will have to import Swap trait into every module where you want to call the method.