Collect elements from an iterator at a specific index

I was wondering if it is possible to use .collect() on an iterator to capture elements at a specific index. For example, if I start with a line, I would usually 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)); 
+5
source share
4 answers

No, it is not; however, you can easily filter before collecting, which in practice achieves the same effect.

If you want to filter by index, you need to add the index and then delete it later:

  • enumerate (to add an index to an element)
  • filter based on this index
  • map to remove an index from an element

Or in the 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 want to get only one index (and therefore an element), then using nth much easier. It returns 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 only want the first element that matches, then collecting in Vec inefficient: it will consume the entire iterator (without laziness) and allocate potentially a lot of memory, which is not needed at all.

That way, you better just query the first element using the next iterator method, which returns 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 can also use skip and take before building, but I think you already have the alternatives presented here.

+7
source

There is an nth function on Iterator that does the following:

 let text = line.split(" ").nth(3).unwrap(); 
+6
source

No; you can use take and next though:

 let line = "Some line of text for example"; let l = line.split(" "); let text = l.skip(3).next(); 

Note that this leads to the fact that text is Option<&str> , since there is no guarantee that the sequence has at least four elements.

Addendum : using nth clearly shorter, although I prefer to be explicit in that accessing the n th element of the iterator necessarily consumes all the elements before this.

+2
source

For those who may be interested, you can do many interesting things with iterators (thanks Matthieu M), for example, to get a few words from a string according to their index, you can use filter along with boolean or || to check multiple indexes!

 let line = "FCC2CCMACXX:4:1105:10758:14389# 81 chrM 1 32 10S90M = 16151 16062" let words: Vec<&str> = line.split(" ") .enumerate() .filter(|&(i, _)| i==1 || i==3 || i==6 ) .map(|(_, e) | e) .collect(); 
0
source

All Articles