I'm trying to convert a HashSet<String> into a sorted vector that can then be joined with commas:
use std::collections::HashSet;
fn main() {
let mut hs = HashSet::<String>::new();
hs.insert(String::from("fee"));
hs.insert(String::from("fie"));
hs.insert(String::from("foo"));
hs.insert(String::from("fum"));
let mut v: Vec<&String> = hs.iter().collect();
v.sort();
println!("{}", v.join(", "));
}
This will not compile:
error[E0599]: no method named `join` found for struct `std::vec::Vec<&std::string::String>` in the current scope
--> src/main.rs:13:22
|
13 | println!("{}", v.join(", "));
| ^^^^ method not found in `std::vec::Vec<&std::string::String>`
I understand why I can't join the Vec<&String>, but how can I convert the HashSet to a Vec<String> instead, so it can be joined?
The examples given in What's an idiomatic way to print an iterator separated by spaces in Rust? do not seem to apply because the iterator for Args returns String values, unlike the iterator for HashSet which returns &String.
I encourage you to re-read The Rust Programming Language, specifically the chapter on iterators. Next, become familiar with the methods of Iterator.
The normal way I'd expect to see this implemented is to convert the HashSet to an iterator and then collect the iterator to a Vec:
let mut v: Vec<_> = hs.into_iter().collect();
In this case, I'd prefer to use FromIterator directly (the same trait that powers collect):
let mut v = Vec::from_iter(hs);
Focusing on your larger problem, use a BTreeSet instead, coupled with What's an idiomatic way to print an iterator separated by spaces in Rust?
use itertools::Itertools; // 0.10.1
use std::collections::BTreeSet;
fn main() {
// Create the set somehow
let hs: BTreeSet<_> = ["fee", "fie", "foo", "fum"]
.into_iter()
.map(String::from)
.collect();
println!("{}", hs.iter().format(", "));
}
There's a straightforward way to convert a HashSet of Strings into a Vec of Strings using the turbofish (::<>):
let result_vec = result_set.into_iter().collect::<Vec<_>>();
Related
I try to wait and remove one-by-one future from a Vec of futures. It does not work. I understand why it does not work: Pin is not copyable. But how to correct this error?
extern crate futures;
use std::cell::{RefCell};
use std::rc::Rc;
use std::pin::Pin;
use std::future::Future;
use futures::channel::oneshot::Canceled;
use futures::executor::block_on;
use futures::future::select_all;
fn run_queries_body() {
let _futures: Vec<Pin<Box<dyn Future<Output=Result<(), Canceled>>>>> = Vec::new();
let futuresRc = Rc::new(RefCell::new(_futures)); // TODO: Cell instead
// This in actual could be called inside another future, so we need Rc<RefCell<...>>
let mut futures = futuresRc.borrow_mut();
let f3 = futures.iter().map(|x| *x);
let (_res, _idx, remaining_futures) = block_on(select_all(f3));
*futures = remaining_futures;
}
error[E0507]: cannot move out of `*x` which is behind a shared reference
--> src/lib.rs:16:37
|
16 | let f3 = futures.iter().map(|x| *x);
| ^^ move occurs because `*x` has type `std::pin::Pin<std::boxed::Box<dyn futures::Future<Output = std::result::Result<(), futures::channel::oneshot::Canceled>>>>`, which does not implement the `Copy` trait
The problem is not in the pin - a boxed future is safe to move along with its pin because box means the future is heap-allocated, so moving the box doesn't move the future. The pin serves to forbid moving the future out of its box, but you don't attempt that. Your code fails to compile because Vec::iter() iterates over references to elements, and you can't move an object out of a reference because it would leave the original value in an undefined state. This kind of move is only allowed for types that can be trivially copied such as numbers or bools, which is marked by the Copy trait. The compiler's message is confusing because it mentions Pin<...>, but it only does so because that's the literal type behind the reference, and the compiler reports that the type in question isn't Copy, without implying anything about Pin semantics.
A straightforward fix is to make futures a vector of options. That allows you to extract an element out of the vector just by possessing a mutable iterator to the element by calling Option::take on the &mut Option<T>. This is well-defined because it extracts the value, but also leaves None in the old place in the vector.
In your case you would iterate over the vector using iter_mut() (playground):
pub fn run_queries_body() {
let futures: Vec<Option<Pin<Box<dyn Future<Output = Result<(), Canceled>>>>>> = vec![];
let futures_rc = Rc::new(RefCell::new(futures));
let mut futures = futures_rc.borrow_mut();
let f3 = futures.iter_mut().map(|f| f.take().unwrap());
let (_res, _idx, remaining_futures) = block_on(select_all(f3));
*futures = remaining_futures.into_iter().map(Some).collect();
}
As pointed out by #Jmb, an even simpler approach is to use Vec::drain, which removes the elements from the vector and gives you an iterator over the removed elements (playground):
pub fn run_queries_body() {
let futures: Vec<Pin<Box<dyn Future<Output = Result<(), Canceled>>>>> = vec![];
let futures_rc = Rc::new(RefCell::new(futures));
let mut futures = futures_rc.borrow_mut();
let f3 = futures.drain(..);
let (_res, _idx, remaining_futures) = block_on(select_all(f3));
*futures = remaining_futures;
}
What is the right way to have multiple std::collections::LinkedLists where the number of those lists is unknown at compile time?
I'm filling them with data as well as merging them (e.g. using append()).
I thought it would be good to have a vector that contains those lists, or contains references to those lists.
I have tried the following:
use std::collections::LinkedList;
fn listtest() {
let mut v: Vec<LinkedList<i32>> = Vec::new();
v.push(LinkedList::new()); // first list
v.push(LinkedList::new()); // second list
v[0].push_back(1); // fill with data
v[1].push_back(3); // fill with data
v[0].append(&mut v[1]); // merge lists
}
fn main() {
listtest();
}
This fails to compile because I have two mutable references of v when using append(). I also tried using Vec<&mut LinkedList<i32>>, but did not succeed.
What would be the right approach to this problem?
There is no right approach. One possibility is to use split_at_mut. This creates two separate slices, each of which can be mutated separately from the other:
use std::collections::LinkedList;
fn main() {
let mut v = vec![LinkedList::new(), LinkedList::new()];
v[0].push_back(1);
v[1].push_back(3);
{
let (head, tail) = v.split_at_mut(1);
head[0].append(&mut tail[0]);
}
println!("{:?}", v);
}
See:
How to get mutable references to two array elements at the same time?
How can I write data from a slice to the same slice?
How to operate on 2 mutable slices of a Rust array
etc.
Most collections have an iter_mut method that returns an iterator that yields mutable references to each item in the collection. And these references can all be used at the same time! (But the references must come from the same iterator; you can't use references coming from separate calls to iter_mut concurrently.)
use std::collections::LinkedList;
fn listtest() {
let mut v: Vec<LinkedList<i32>> = Vec::new();
v.push(LinkedList::new()); // first list
v.push(LinkedList::new()); // second list
v[0].push_back(1); // fill with data
v[1].push_back(3); // fill with data
let mut vi = v.iter_mut();
let first = vi.next().unwrap();
let second = vi.next().unwrap();
first.append(second); // merge lists
}
fn main() {
listtest();
}
Also remember that iterators have the nth method for doing the equivalent of next in a loop.
This question already has an answer here:
How do I create a heterogeneous collection of objects?
(1 answer)
Closed 5 years ago.
In the context of converting a infix expression to a postfix one, using the Shunting-yard algorithm. I want to use a vector to store the output, which would store both operator and numeric type data.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Operator {
Add,
Sub,
Mul,
Div,
}
fn main() {
let mut output: Vec<String> = Vec::new(); // create an output vector
let a = 2;
let b = Operator::Add;
let c = 3;
output.push(a.to_string());
output.push(b.to_string());
output.push(c.to_string());
}
This above code of course doesn't compile, since the to_string() method is not defined for Operator. I see two ways to fix it:
Define a to_string() method
Create a vector to store references to numbers and Operator.
I think the second is the preferred choice, though I don't know if creating a vector of references will introduce lots of complexity.
There's no need to use references; just store the numbers and Operators directly in an enum:
enum Thing {
Op(Operator),
Number(i32),
}
fn main() {
let mut output: Vec<Thing> = Vec::new();
let a = 2;
let b = Operator::Add;
let c = 3;
output.push(Thing::Number(a));
output.push(Thing::Op(b));
output.push(Thing::Number(c));
}
And then match on them when taking them out.
I want to build a HashSet<u8> from a Vec<u8>. I'd like to do this
in one line of code,
copying the data only once,
using only 2n memory,
but the only thing I can get to compile is this piece of .. junk, which I think copies the data twice and uses 3n memory.
fn vec_to_set(vec: Vec<u8>) -> HashSet<u8> {
let mut victim = vec.clone();
let x: HashSet<u8> = victim.drain(..).collect();
return x;
}
I was hoping to write something simple, like this:
fn vec_to_set(vec: Vec<u8>) -> HashSet<u8> {
return HashSet::from_iter(vec.iter());
}
but that won't compile:
error[E0308]: mismatched types
--> <anon>:5:12
|
5 | return HashSet::from_iter(vec.iter());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u8, found &u8
|
= note: expected type `std::collections::HashSet<u8>`
= note: found type `std::collections::HashSet<&u8, _>`
.. and I don't really understand the error message, probably because I need to RTFM.
Because the operation does not need to consume the vector¹, I think it should not consume it. That only leads to extra copying somewhere else in the program:
use std::collections::HashSet;
use std::iter::FromIterator;
fn hashset(data: &[u8]) -> HashSet<u8> {
HashSet::from_iter(data.iter().cloned())
}
Call it like hashset(&v) where v is a Vec<u8> or other thing that coerces to a slice.
There are of course more ways to write this, to be generic and all that, but this answer sticks to just introducing the thing I wanted to focus on.
¹This is based on that the element type u8 is Copy, i.e. it does not have ownership semantics.
The following should work nicely; it fulfills your requirements:
use std::collections::HashSet;
use std::iter::FromIterator;
fn vec_to_set(vec: Vec<u8>) -> HashSet<u8> {
HashSet::from_iter(vec)
}
from_iter() works on types implementing IntoIterator, so a Vec argument is sufficient.
Additional remarks:
you don't need to explicitly return function results; you only need to omit the semi-colon in the last expression in its body
I'm not sure which version of Rust you are using, but on current stable (1.12) to_iter() doesn't exist
Converting Vec to HashSet
Moving data ownership
let vec: Vec<u8> = vec![1, 2, 3, 4];
let hash_set: HashSet<u8> = vec.into_iter().collect();
Cloning data
let vec: Vec<u8> = vec![1, 2, 3, 4];
let hash_set: HashSet<u8> = vec.iter().cloned().collect();
I'm trying to convert Vec<&str> to Vec<u16> but I can't figure out a functional way to do it.
let foo: &str = "1,2,3"; // Parsing a string here
let bar: Vec<&str> = foo.split(",").collect(); // Bar is a nice vector of &str's
I need to get bar into a Vec<u16>.
There's an iterator adapter map! You'd use it like this:
let bar: Vec<u16> = foo.split(",").map(|x| x.parse::<u16>().unwrap()).collect();
parse is a library function that relies on the trait FromStr, and it can return an error, so we need to unwrap() the error type. (This is a good idea for a short example, but in real code, you will want to handle the error properly - if you have a value that's not a u16 there, your program will just crash).
map takes a closure that takes it's parameter by value and then returns the iterator obtained by lazily applying that function. You're collecting all of the values here, but if you only take(5) of them, you would only parse 5 of the strings.
You haven't fully specified your problem. Specifically, what should happen when one of the strings cannot be parsed into a number? When you parse a number from a string using parse, it can fail. That is why the function returns a Result:
fn parse<F>(&self) -> Result<F, F::Err>
where
F: FromStr,
Here's a solution that takes the vector, gets an iterator with iter, changes each item using map and ultimately returns a Result using collect. If the parsing was a success, you get an Ok. If any failed, you get an Err:
fn main() {
let input = "1,2,3";
let strings: Vec<_> = input.split(",").collect();
let numbers: Result<Vec<u16>, _> = strings.iter().map(|x| x.parse()).collect();
println!("{:?}", numbers);
}
Or you could remove failed conversions by filtering out Err values with flat_map:
fn main() {
let input = "1,2,3";
let strings: Vec<_> = input.split(",").collect();
let numbers: Vec<u16> = strings.iter().flat_map(|x| x.parse()).collect();
println!("{:?}", numbers);
}
Of course, it's a bit silly to convert the string into a vector of strings and then convert it again to a vector of integers. If you actually have a comma-separated string and want numbers, do it in one go:
fn main() {
let input = "1,2,3";
let numbers: Result<Vec<u16>, _> = input.split(",").map(|x| x.parse()).collect();
println!("{:?}", numbers);
}
See also:
Why does `Option` support `IntoIterator`?
My take as someone not really experienced in Rust yet.
fn main() {
let foo: &str = "1,2,3"; // Parsing a string here
let bar: Vec<&str> = foo.split(",").collect(); // Bar is a nice vector of &str's
// here the magic happens
let baz = bar.iter().map(|x| x.parse::<i64>());
for x in baz {
match x {
Ok(i) => println!("{}", i),
Err(_) => println!("parse failed"),
}
}
}
Note that since parse returns a Result, you have to extract the value from each parsed element. You might want to behave in a different way, e.g. filter only the succeeded results.