Collect Vec<char> from Lines iterator


#1

Hi,

I am trying (in the big picture) to read lines from a file and extract every character from every lines Lines -> Vec<char> (schematically). I tried the following

let lines = "Foo\nBar\nFizz\nBuzz";
let strs = lines.lines().collect::<Vec<&str>>();
let chars = strs.iter().map(|s| s.chars()).collect::<Vec<char>>();

with the following error message :

error[E0277]: a collection of type `std::vec::Vec<char>` cannot be built from an iterator over elements of type `std::str::Chars<'_>`
 --> src/main.rs:5:44
  |
5 | let chars = strs.iter().map(|s| s.chars()).collect::<Vec<char>>();
  |                                            ^^^^^^^ a collection of type `std::vec::Vec<char>` cannot be built from `std::iter::Iterator<Item=std::str::Chars<'_>>`
  |
  = help: the trait `std::iter::FromIterator<std::str::Chars<'_>>` is not implemented for `std::vec::Vec<char>`

Can someone explain why it does not work and how to circumvent it?

Here is a link to a playground.


#2

As is, you’ve mapped to an iterator where the items are Chars iterators, so collecting that would give you something like Vec<Chars>.

If you’re aiming for a single Vec<char> containing the characters from every line all together, then use flat_map instead of map. If you really want the characters from each line separately, something like Vec<Vec<char>>, then you should collect the inner Vec within the map, and then collect that into the outer Vec.


#3

Thanks a lot for your answer.
I have settled, thanks to your answer, on this piece of code which compiles and works properly :

let lines = "Foo\nBar\nFizz\nBuzz";
let strs = lines.lines().collect::<Vec<&str>>();
let chars = strs.iter().map(|s| s.chars().collect()).collect::<Vec<Vec<char>>>();

Do you see any other way to write it more concisely ?


#4

Do you need the strs intermediate elsewhere? If not, you could just use lines().map(...) directly.


#5

Will do! Thanks!