1

This code doesn't compile:

use indexmap::IndexMap;
use either::Either;

type Atom = Either<IndexMap<String, u64>, Vec<String>>;

fn flatten(atoms: Vec<Option<Atom>>) -> Vec<String> {
    atoms.into_iter()
    .filter(Option::is_some)
    .map(|atom| match atom.unwrap() {
        Either::Left(map) => map.into_keys().into_iter(),
        Either::Right(vec) => vec.into_iter(),
    })
    .flatten()
    .collect()
}
9  |       .map(|atom| match atom.unwrap() {
   |  _________________-
10 | |         Either::Left(map) => map.into_keys().into_iter(),
   | |                              --------------------------- this is found to be of type `indexmap::map::IntoKeys<String, u64>`
11 | |         Either::Right(vec) => vec.into_iter(),
   | |                               ^^^^^^^^^^^^^^^ expected `IntoKeys<String, u64>`, found `IntoIter<String>`
12 | |     })
   | |_____- `match` arms have incompatible types
   |
   = note: expected struct `indexmap::map::IntoKeys<String, u64>`
              found struct `std::vec::IntoIter<String>`

There's two ways I can solve this that I know of, but none that I am happy with:

  • Use Box + dyn: Dynamic polymorphism overhead
  • Collect into a Vec beforehand before collecting: More efficient to flatten the iterators then collect rather than allocating two vec's then allocating a new one again

Is there a better option than the two?

1
  • Use Either. itertools provide one, or the either crate. Commented Apr 22 at 22:30

1 Answer 1

2

use map_either to convert it into an Either of two iterators, then it acts as an iterator if both iterators have the same item type, or you can call into_iter on it.

use indexmap::IndexMap;
use either::Either;

type Atom = Either<IndexMap<String, u64>, Vec<String>>;

fn flatten(atoms: Vec<Option<Atom>>) -> Vec<String> {
    atoms.into_iter()
        .filter(Option::is_some)
        .map(Option::unwrap)
        .map(|atom| atom.map_either(
                |map| map.into_keys().into_iter(),
                |vec| vec.into_iter()
            )/*.into_iter()*/
        )
        .flatten()
        .collect()
}

run on playground

Sign up to request clarification or add additional context in comments.

1 Comment

.map(…).flatten() is better written as .flat_map(…) similarly .filter(Option::is_some).map(Option::unwrap) is just .filter_map(|x| x)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.