vector - Is it more efficient to slice an array or use Iterator::skip? -


i want call function each element in slice [0+k .. n], k offset , n number of elements in vector. importantly, want index of element original slice.

i have found 2 ways of doing this:

  1. use enumerate , skip beginning items

    vec.iter().enumerate().skip(k).map(|(i, v)| (f(v), i)).min() 
  2. take subslice , add offset index `enumerate

    vec[k..].iter().enumerate().map(|(i, v)| (f(v), + k)).min() 

in both cases, vec vector of strings, , f returns specific character in string (v.chars().nth(offset)). of these solutions efficient?

let's use code example. it's similar example, bit simpler:

fn main() {     let items = ["a", "bb", "ccc", "dddd", "eeeee"];     let k = 3;      let 1 = items.iter().enumerate().skip(k).map(|(i, v)| (v.len(), i));     let 2 = items[k..].iter().enumerate().map(|(i, v)| (v.len(), + k));      // sanity check results same     let items1: vec<_> = one.collect();     let items2: vec<_> = two.collect();      println!("{}", items1 == items2); } 

which more performant tricky topic. rust , llvm have optimizations can make code quite fast.

based purely on gut feeling, use first 1 if knew going skip "a few" of items, , second 1 if didn't know how many or if lot.

in first case, conceptually have iterate through of items want skip over. possible optimizer reduce down, it's complicated interaction enumerate , map, wouldn't count on without inspecting assembly.

the second 1 (items[k..]) uses subslicing, o(1) operation it's going index chunk of memory. addition simple.

however, true test profiling. create large input array , start part way:

fn main() {     let items = ["a", "bb", "ccc", "dddd", "eeeee"];     let items: vec<_> = items.iter().cycle().take(10_000_000).collect();      let k = 371_223;      // let 1 = items.iter().enumerate().skip(k).map(|(i, v)| (v.len(), i));     let 2 = items[k..].iter().enumerate().map(|(i, v)| (v.len(), + k));      // let items1: vec<_> = one.collect();     let items2: vec<_> = two.collect();      // println!("{}", items1.len());     println!("{}", items2.len()); } 

running code, compiled optimizations, has following times averaged on 10 runs:

  1. 153.6ms
  2. 160.1ms

so, contrary gut feeling said, first version faster. it's entirely possible benchmarking incorrect, that's why should benchmarking on real code.

also, note really fast either way. that's 15 or 16 nanoseconds per item. what's 1 nanosecond among friends?


Comments

Popular posts from this blog

java - Date formats difference between yyyy-MM-dd'T'HH:mm:ss and yyyy-MM-dd'T'HH:mm:ssXXX -

c# - Get rid of xmlns attribute when adding node to existing xml -