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:
use
enumerate
,skip
beginning itemsvec.iter().enumerate().skip(k).map(|(i, v)| (f(v), i)).min()
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:
- 153.6ms
- 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
Post a Comment