I am trying to create a HashMap using functional programming and utilizing parallelization by rayon.
If I try this without rayon, it works:
use std::collections::HashMap;
fn main() {
let nums = [1, 2, 1, 2, 1, 2];
let result: HashMap<i32, i32> =
nums.iter()
.filter(|x| *x % 2 == 0)
.fold(HashMap::new(), |mut acc, x| {
*acc.entry(*x).or_insert(0) += 1;
acc
});
println!("{:?}", result);
}
If I try to use multiple cores by switching from iter() to par_iter(), I get an error:
use rayon::prelude::*; // 1.5.1
use std::collections::HashMap;
fn main() {
let nums = [1, 2, 1, 2, 1, 2];
let result: HashMap<i32, i32> =
nums.par_iter()
.filter(|x| *x % 2 == 0)
.fold(HashMap::new(), |mut acc, x| {
*acc.entry(*x).or_insert(0) += 1;
acc
});
println!("{:?}", result);
}
error[E0277]: expected a `Fn<()>` closure, found `HashMap<_, _>`
--> src/main.rs:9:19
|
9 | .fold(HashMap::new(), |mut acc, x| {
| ^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `HashMap<_, _>`
|
= help: the trait `Fn<()>` is not implemented for `HashMap<_, _>`
= note: wrap the `HashMap<_, _>` in a closure with no arguments: `|| { /* code */ }`
error[E0308]: mismatched types
--> src/main.rs:7:9
|
6 | let result: HashMap<i32, i32> =
| ----------------- expected due to this
7 | / nums.par_iter()
8 | | .filter(|x| *x % 2 == 0)
9 | | .fold(HashMap::new(), |mut acc, x| {
10 | | *acc.entry(*x).or_insert(0) += 1;
11 | | acc
12 | | });
| |______________^ expected struct `HashMap`, found struct `Fold`
|
= note: expected struct `HashMap<i32, i32>`
found struct `Fold<rayon::iter::Filter<rayon::slice::Iter<'_, {integer}>, [closure#src/main.rs:8:21: 8:36]>, HashMap<_, _>, _>`
Obviously, Rust tries to stop me from doing something stupid involving race conditions, but how would I build a HashMap inside a par_iter()?
Rayon's fold creates intermediate items (cannot be known how many). From the documentation (emphasis mine):
Parallel fold is similar to sequential fold except that the
sequence of items may be subdivided before it is
folded. Consider a list of numbers like 22 3 77 89 46. If
you used sequential fold to add them (fold(0, |a,b| a+b),
you would wind up first adding 0 + 22, then 22 + 3, then 25 +
77, and so forth. The parallel fold works similarly except
that it first breaks up your list into sublists, and hence
instead of yielding up a single sum at the end, it yields up
multiple sums. The number of results is nondeterministic, as
is the point where the breaks occur.
You need to reduce those intermediate items into the final one:
use rayon::prelude::*; // 1.5.1
use std::collections::HashMap;
fn main() {
let nums = [1, 2, 1, 2, 1, 2];
let result: HashMap<i32, i32> = nums
.par_iter()
.filter(|x| *x % 2 == 0)
.fold(HashMap::new, |mut acc, x| {
*acc.entry(*x).or_insert(0) += 1;
acc
})
.reduce_with(|mut m1, m2| {
for (k, v) in m2 {
*m1.entry(k).or_default() += v;
}
m1
})
.unwrap();
println!("{:?}", result);
}
Playground
Also note that the first parameter of Rayon's fold is a function that creates the empty HashMap, not an empty HashMap like the standard library's fold.
Related
I am trying to write quick sort in Rust, I got it working when I used the specific type [i32] but I get an error when I try to use [T].
fn main() {
let mut arr = vec![4,3,2,1];
quick_sort(&mut arr);
println!("{:?}", arr);
}
fn partition<T: Ord>(slice: &mut [T]) -> usize {
let end = slice.len() - 1;
let pivot = slice[end];
let mut j = 0;
for i in 0..end {
if slice[j] <= pivot {
slice.swap(i, j);
j += 1;
}
}
slice.swap(end, j);
j
}
fn quick_sort<T: Ord>(slice: &mut [T]) {
if !slice.is_empty() {
let j = partition(slice);
let len = slice.len();
quick_sort(&mut slice[0..j]);
quick_sort(&mut slice[j+1..len]);
}
}
I get the following error:
error[E0508]: cannot move out of type `[T]`, a non-copy slice
--> src/main.rs:9:17
|
9| let pivot = slice[end];
| ^^^^^^^^^^ cannot move out of here
| move occurs because `slice[_]` has type `T`,
| which does not implement the `Copy` trait
| help: consider borrowing here: `&slice[end]`
When let pivot = &slice[end]; , I get a different error:
error[E0308]: mismatched types
--> src/main.rs:12:22
|
7| fn partition<T: Ord>(slice: &mut [T]) -> usize {
| - this type parameter
...
12| if slice[j] <= pivot {
| ^^^^^ expected type parameter `T`, found `&T`
= note: expected type parameter `T`
found reference `&T`
I cannot get this to work with [T].
We can fix the "expected type parameter T, found &T" error by changing the if to:
if &slice[j] <= pivot {
but that runs into another error:
error[E0502]: cannot borrow `*slice` as mutable because it is also borrowed as immutable
--> src/main.rs:13:13
|
9 | let pivot = &slice[end];
| ----------- immutable borrow occurs here
...
12 | if &slice[j] <= pivot {
| ----- immutable borrow later used here
13 | slice.swap(i, j);
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here
This is because we are taking a reference to a value from the slice and while that reference is alive, we are calling a method that requires mutable access to the slice.
To fix this, we can inline the referencing into the if statement itself:
fn partition<T: Ord>(slice: &mut [T]) -> usize {
let end = slice.len() - 1;
let mut j = 0;
for i in 0..end {
if slice[j] <= slice[end] {
slice.swap(i, j);
j += 1;
}
}
slice.swap(end, j);
j
}
Output:
[1, 2, 3, 4]
Playground
The reason this worked for [i32] is because calling slice[end] implicitly created a copy of the value because i32 implements the Copy trait. If a type does not implement Copy, you need to either take a reference using &slice[index] or if it implements Clone, call slice[index].clone(). In this code you have a generic T which does not implement either of those.
I encountered an error when trying to use a function get_even_numbers() to borrow a vec v by passing it in by reference &v instead of by value v.
fn get_even_numbers(v: &Vec<i32>) -> Vec<i32> {
v.iter().filter(|x| x % 2 == 0).collect()
}
fn main() {
let v: Vec<i32> = (0..10).collect();
let even: Vec<i32> = get_even_numbers(&v);
println!("Even numbers: {:?}", even);
}
error[E0277]: a value of type `Vec<i32>` cannot be built from an iterator over elements of type `&i32`
--> src/main.rs:2:37
|
2 | v.iter().filter(|x| x % 2 == 0).collect()
| ^^^^^^^ value of type `Vec<i32>` cannot be built from `std::iter::Iterator<Item=&i32>`
|
= help: the trait `FromIterator<&i32>` is not implemented for `Vec<i32>`
= help: the trait `FromIterator<T>` is implemented for `Vec<T>`
note: required by a bound in `collect`
Why does the above give an error, but passing it in by value does not, as shown below?
fn get_even_numbers(v: Vec<i32>) -> Vec<i32> {
v.into_iter().filter(|x| x % 2 == 0).collect()
}
fn main() {
let v: Vec<i32> = (0..10).collect();
let even: Vec<i32> = get_even_numbers(v);
println!("Even numbers: {:?}", even);
}
Even numbers: [0, 2, 4, 6, 8]
I used .iter() inside the function when passing in by reference and .into_iter() when passing in by value, not sure if these are the correct functions to use.
Use v.iter().filter(|x| x % 2 == 0).cloned().collect(). That will (trivially) clone each of the &i32 references into actual i32 values.
This question already has answers here:
Expected closure, found a different closure
(2 answers)
What is the inferred type of a vector of closures?
(1 answer)
Closed 4 years ago.
I'm trying to build a simple RPN calculator, and I've got the basics working. I'd like to make a dispatch table to implement the various calculator functions. If I were doing this in Perl, I would write something like:
my %ops = (
'+' => sub { +shift + +shift; },
'-' => sub { +shift - +shift; },
'*' => sub { +shift * +shift; },
'/' => sub { +shift / +shift; }
);
or in JavaScript:
let ops = {
"+": (a, b) => a + b,
"-": (a, b) => a - b,
"*": (a, b) => a * b,
"/": (a, b) => a / b
};
This is what I've tried so far in Rust:
use std::collections::HashMap;
fn main() {
println!("Going to call +");
let dispatch = HashMap::new();
dispatch.insert(String::from("+"), |a, b| a + b);
dispatch.insert(String::from("-"), |a, b| a - b);
let plus = dispatch.get(&String::from("+"));
println!("2 + 3 = {}", plus(2, 3));
let minus = dispatch.get(&String::from("-"));
println!("2 - 3 = {}", minus(2, 3));
}
When I try compiling, I get these errors:
error[E0308]: mismatched types
--> src/main.rs:9:40
|
9 | dispatch.insert(String::from("-"), |a, b| a - b);
| ^^^^^^^^^^^^ expected closure, found a different closure
|
= note: expected type `[closure#src/main.rs:8:40: 8:52]`
found type `[closure#src/main.rs:9:40: 9:52]`
= note: no two closures, even if identical, have the same type
= help: consider boxing your closure and/or using it as a trait object
error[E0618]: expected function, found enum variant `plus`
--> src/main.rs:12:28
|
11 | let plus = dispatch.get(&String::from("+"));
| ---- `plus` defined here
12 | println!("2 + 3 = {}", plus(2, 3));
| ^^^^^^^^^^ not a function
help: `plus` is a unit variant, you need to write it without the parenthesis
|
12 | println!("2 + 3 = {}", plus);
| ^^^^
error[E0618]: expected function, found enum variant `minus`
--> src/main.rs:15:28
|
14 | let minus = dispatch.get(&String::from("-"));
| ----- `minus` defined here
15 | println!("2 - 3 = {}", minus(2, 3));
| ^^^^^^^^^^^ not a function
help: `minus` is a unit variant, you need to write it without the parenthesis
|
15 | println!("2 - 3 = {}", minus);
| ^^^^^
What does "no two closures, even if identical, have the same type" mean? How can I make a HashMap hold a closure, and then call it?
It sounds like using Box would fix it... Like I said, I'm pretty new, and I haven't used Box. How do I get what's in the box out of the box?
There are a few orthogonal issues here. First and foremost, your hashmap is immutable. You use let instead of let mut, which is good practice, but in order to be able to insert into it, we need it to (at least initially) be let mut. If you're planning to modify the hashmap after the initial construction, you may want to let mut the dispatch variable as well.
let dispatch = {
let mut temp = HashMap::new();
temp.insert(String::from("+"), |a, b| a + b);
temp.insert(String::from("-"), |a, b| a - b);
temp
};
Now you need an explicit type for your hashmap. The two closures you've defined, as far as the compiler is concerned, are of entirely distinct types. However, they are both compatible with fn(i32, i32) -> i32, the type of binary functions on i32 (you can replace i32 with a different numerical type if you wish), so let's make the type explicit.
let dispatch = {
let mut temp: HashMap<String, fn(i32, i32) -> i32> = HashMap::new();
temp.insert(String::from("+"), |a, b| a + b);
temp.insert(String::from("-"), |a, b| a - b);
temp
};
Finally, HashMap.get returns an std::option::Option, not a direct value, so we need to unwrap it. get returns None if the key isn't found. If this was a large project, we'd handle that error appropriately, perhaps by logging it or telling the user, but for something simple like this, we simply need to use expect, which essentially tells the compiler "Yes, I know this could go horribly wrong. I'm willfully ignoring that fact." which is perfectly fine for our simple example.
let plus = dispatch.get(&String::from("+")).expect("Couldn't find +");
let minus = dispatch.get(&String::from("-")).expect("Couldn't find -");
Complete example
use std::collections::HashMap;
fn main() {
let dispatch = {
let mut temp: HashMap<String, fn(i32, i32) -> i32> = HashMap::new();
temp.insert("+".into(), |a, b| a + b);
temp.insert("-".into(), |a, b| a - b);
temp
};
let plus = dispatch["+"];
println!("2 + 3 = {}", plus(2, 3));
let minus = dispatch["-"];
println!("2 - 3 = {}", minus(2, 3));
}
Note that you can replace String with &'static str:
let dispatch = {
let mut temp: HashMap<_, fn(i32, i32) -> i32> = HashMap::new();
temp.insert("+", |a, b| a + b);
temp.insert("-", |a, b| a - b);
temp
};
How can I get a mutable reference to an item found in a vector?
I've tried the following which works if I don't make the iterator mutable using .iter():
fn main() {
let mut vec = vec![1, 2, 3, 4];
let mut wrong = -1;
let working = match vec.iter().find(|&c| *c == 2) {
Some(c) => c,
None => &wrong
};
println!("Result: {}", working);
}
But when I try to get a mutable reference using a mutable iterator .iter_mut(),
fn main() {
let mut vec = vec![1, 2, 3, 4];
let mut wrong = -1;
let mut error = match vec.iter_mut().find(|&c| *c == 2) {
Some(c) => c,
None => &mut wrong
};
println!("Result: {}", error);
}
I get the following error:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:5:48
|
5 | let mut error = match vec.iter_mut().find(|&c| *c == 2) {
| ^-
| ||
| |hint: to prevent move, use `ref c` or `ref mut c`
| cannot move out of borrowed content
I also tried to make the type in the closure mutable with |&mut c| but that gives the following error:
error[E0308]: mismatched types
--> src/main.rs:5:48
|
5 | let mut error = match vec.iter_mut().find(|&mut c| *c == 2) {
| ^^^^^^ types differ in mutability
|
= note: expected type `&&mut {integer}`
found type `&mut _`
= help: did you mean `mut c: &&&mut {integer}`?
Rust's .find passes the callback the type &Self::Item, and since you are using .iter_mut(), you've created an iterator where each item is &mut T. That means the type passed to your find callback is &&mut T. To get that to typecheck, you can do either
vec.iter_mut().find(|&&mut c| c == 2)
or
vec.iter_mut().find(|c| **c == 2)
with the second one being preferable.
The error you are getting is because the middle-ground you've chosen by using &c would set c to a value of &mut T, and one of Rust's big rules is that multiple things can't own a mutable reference to an item at the same time. Your non-mutable case works because you are allowed to have multiple immutable references to an item.
I'm trying to find the dot product of two vectors:
fn main() {
let a = vec![1, 2, 3, 4];
let b = a.clone();
let r = a.iter().zip(b.iter()).map(|x, y| Some(x, y) => x * y).sum();
println!("{}", r);
}
This fails with
error: expected one of `)`, `,`, `.`, `?`, or an operator, found `=>`
--> src/main.rs:4:58
|
4 | let r = a.iter().zip(b.iter()).map(|x, y| Some(x, y) => x * y).sum();
| ^^ expected one of `)`, `,`, `.`, `?`, or an operator here
I've also tried these, all of which failed:
let r = a.iter().zip(b.iter()).map(|x, y| => x * y).sum();
let r = a.iter().zip(b.iter()).map(Some(x, y) => x * y).sum();
What is the correct way of doing this?
(Playground)
In map(), you don't have to deal with the fact that the iterator returns an Option. This is taken care of by map(). You need to supply a function taking the tuple of both borrowed values. You were close with your second try, but with the wrong syntax. This is the right one:
a.iter().zip(b.iter()).map(|(x, y)| x * y).sum()
Your final program required an annotation on r:
fn main() {
let a = vec![1, 2, 3, 4];
let b = a.clone();
let r: i32 = a.iter().zip(b.iter()).map(|(x, y)| x * y).sum();
println!("{}", r);
}
(Playground)
See also:
Why can't Rust infer the resulting type of Iterator::sum?
How do I sum a vector using fold?
More info on the closure passed to map: I have written ...map(|(x, y)| x * y), but for more complicated operations you would need to delimit the closure body with {}:
.map(|(x, y)| {
do_something();
x * y
})