Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Collect items from an iterator at a specific index

Tags:

rust

I was wondering if it is possible to use .collect() on an iterator to grab items at a specific index. For example if I start with a string, I would normally do:

let line = "Some line of text for example";
let l = line.split(" ");
let lvec: Vec<&str> = l.collect();
let text = &lvec[3];

But what would be nice is something like:

let text: &str = l.collect(index=(3));
like image 995
kezzos Avatar asked Aug 13 '15 11:08

kezzos


1 Answers

No, it's not; however you can easily filter before you collect, which in practice achieves the same effect.

If you wish to filter by index, you need to add the index in and then strip it afterwards:

  • enumerate (to add the index to the element)
  • filter based on this index
  • map to strip the index from the element

Or in code:

fn main() {
    let line = "Some line of text for example";
    let l = line.split(" ")
                .enumerate()
                .filter(|&(i, _)| i == 3 )
                .map(|(_, e)| e);
    let lvec: Vec<&str> = l.collect();
    let text = &lvec[0];
    println!("{}", text);
}

If you only wish to get a single index (and thus element), then using nth is much easier. It returns an Option<&str> here, which you need to take care of:

fn main() {
    let line = "Some line of text for example";
    let text = line.split(" ").nth(3).unwrap();
    println!("{}", text);
}

If you can have an arbitrary predicate but wishes only the first element that matches, then collecting into a Vec is inefficient: it will consume the whole iterator (no laziness) and allocate potentially a lot of memory that is not needed at all.

You are thus better off simply asking for the first element using the next method of the iterator, which returns an Option<&str> here:

fn main() {
    let line = "Some line of text for example";
    let text = line.split(" ")
                   .enumerate()
                   .filter(|&(i, _)| i % 7 == 3 )
                   .map(|(_, e)| e)
                   .next()
                   .unwrap();
    println!("{}", text);
}

If you want to select part of the result, by index, you may also use skip and take before collecting, but I guess you have enough alternatives presented here already.

like image 101
Matthieu M. Avatar answered Nov 16 '22 03:11

Matthieu M.