These are chat archives for rust-lang/rust

26th
Apr 2017
Elia Schelokov
@thaumant
Apr 26 2017 11:16

Hi all! I'm trying to make this work:

use std::iter::FromIterator;
use std::char::ToUppercase;

fn main() {
    let xs: Vec<&str> = vec!["abcde", "fgh", "ijklmn"];

    let result: Option<Vec<char>> = xs.iter()
        .map(|s| s.chars().nth(4))
        .from_iter()
        .map(|chars| chars.map(|c| c.to_upper()))
        .collect();

    println!("{:?}", result);
}

How do I get an Option<Iterator<Item=T>> from Iterator<Item=Option<T>>? Appplying collect() works but it yields an intermediate vector that I don't need.

Michal 'vorner' Vaner
@vorner
Apr 26 2017 11:36
What do you want to do with None values? If you want to throw them away, .filter might be what you want.
Elia Schelokov
@thaumant
Apr 26 2017 12:38
Basically I want the result to be None if the iterator generates at least one None element.
Michal 'vorner' Vaner
@vorner
Apr 26 2017 12:39
Then you probably want the collect somewhere, otherwise the map and such „stream“ the iterator through.
Like, first value gets through all the maps, etc.
Elia Schelokov
@thaumant
Apr 26 2017 12:51
I consider the None-case an exception, so values getting through all the maps are ok, but having 2 intermediate vectors are not.
I'm actually working with fs::read_dir and collection of Result<T>, this is just a simplified example.
Denis Lisov
@tanriol
Apr 26 2017 12:55
However, the final results are collected in a Vec, aren't they?
Elia Schelokov
@thaumant
Apr 26 2017 12:55
Of course.
But I would like to transform iterator elements from Option<T> to T and then apply some methods like map/filter before collecting.
Denis Lisov
@tanriol
Apr 26 2017 12:59
What's the problem with applying the same methods like map/filter without transforming Option<T> into T?
And BTW, do you expect the first None to end iteration?
Jonas Platte
@jplatte
Apr 26 2017 13:07
@thaumant use .collect<Option<_>>() (or .collect<Result<_, _>>()). It does exactly what you want (if I understand your problem correctly) :)
Elia Schelokov
@thaumant
Apr 26 2017 13:29
@jplatte vec::IntoIter does not implement FromIterator, so I cannot call .collect().
Denis Lisov
@tanriol
Apr 26 2017 13:31
@thaumant What output do you want in case there was a None/Err in the iterator? A None/Err, dropping everything already collected?
Elia Schelokov
@thaumant
Apr 26 2017 13:32

@jplatte, in detail:

let result1: Option<_> = xs.iter()
        .map(|s| s.chars().nth(4))
        .collect();

let result2: Option<Vec<char>> = result1
    .map(|chars| chars.map(|c| c.to_uppercase()))
    .collect();

Tried Option<_>, got error: the type of this value must be known in this context for value chars.map(|c| c.to_uppercase()).

Then tried Option<vec::IntoIter<char>> got the trait std::iter::FromIterator<char> is not implemented for std::vec::IntoIter<char>.

@tanriol Yes, and I would like the first Err to be the result.
Denis Lisov
@tanriol
Apr 26 2017 13:39

Ok, so it works fine as

let result: Option<Vec<char>> = xs.iter()
    .map(|s| s.chars().nth(4))
    .map(|chars| chars.map(|c| 'z'))
    .collect();

without any additional tricks...

Elia Schelokov
@thaumant
Apr 26 2017 13:39
Mind blown. How does it map through Iterator + Result?
Denis Lisov
@tanriol
Apr 26 2017 13:41
In the second mapping line there are two map calls. The external one is an Iterator::map and in its closure chars is an Option<char>. The second one is Option::map.
If you want to do it with to_uppercase, please note that its return value is not a char, but an impl Iterator<char>(!)
Elia Schelokov
@thaumant
Apr 26 2017 13:48
Oh, |chars| confused me, it should be like .map(|maybe_char| maybe_char.map(|c| 'z')).
Denis Lisov
@tanriol
Apr 26 2017 13:49
Yeah, I should have renamed it :-)
Elia Schelokov
@thaumant
Apr 26 2017 13:50
let result1: Option<Vec<char>> = xs.into_iter()
        .map(|s| s.chars().nth(4))
        .map(|c| c.and_then(|c| c.to_uppercase().nth(0)))
        .collect();
Denis Lisov
@tanriol
Apr 26 2017 13:51
Well, if this is the correct for your use case handling of c.to_uppercase() having more than one character...
Elia Schelokov
@thaumant
Apr 26 2017 13:54
So, it does solve the example. But is there a way to transform Iterator<Item=Option<T>> into Option<Iterator<Item=T>>?
Denis Lisov
@tanriol
Apr 26 2017 13:56
Not without collecting. You cannot know that the last item is None until you've fetched it and every previous one... and you need to keep them somewhere at that moment.
Elia Schelokov
@thaumant
Apr 26 2017 13:57
Ok, will insert intermediate .collect().iter() then. Thanks.