I can immediately imagine 3 other variants of doing this
- See first whether the entry already exists with
contains_key
, then either insert
or update with get_mut
- Blindly just
insert
, then re-insert
if the first insert returned a previous value
- Build a
HashMap<&str, usize>
first, then convert that (doing the work of inserting twice).
The problem is, what is faster depends on the input data. How many strings there are, how long they are, how long the input Vec is.
I've benchmarked 5 cases:
d1
: Your short example input data
few10k
: 10 unique strings of length 4 in an array with 10000 entries
many10k
: 10000 entries of length ≤8, nearly all unique
long
: 300 unique strings of length 300
mix
: All of the above
Here are the results
test d1_blind ... bench: 331 ns/iter (+/- 5)
test d1_seeing ... bench: 234 ns/iter (+/- 2)
test d1_tushushu ... bench: 230 ns/iter (+/- 4)
test d1_twice ... bench: 232 ns/iter (+/- 4)
test few10k_blind ... bench: 727,628 ns/iter (+/- 4,557)
test few10k_seeing ... bench: 302,445 ns/iter (+/- 3,282)
test few10k_tushushu ... bench: 399,378 ns/iter (+/- 3,870)
test few10k_twice ... bench: 173,828 ns/iter (+/- 2,431)
test long_blind ... bench: 70,604 ns/iter (+/- 233)
test long_seeing ... bench: 93,349 ns/iter (+/- 381)
test long_tushushu ... bench: 69,862 ns/iter (+/- 231)
test long_twice ... bench: 92,118 ns/iter (+/- 292)
test many10k_blind ... bench: 1,060,656 ns/iter (+/- 65,839)
test many10k_seeing ... bench: 1,148,671 ns/iter (+/- 58,452)
test many10k_tushushu ... bench: 957,733 ns/iter (+/- 5,392)
test many10k_twice ... bench: 1,297,526 ns/iter (+/- 57,415)
test mix_blind ... bench: 1,962,634 ns/iter (+/- 7,973)
test mix_seeing ... bench: 1,617,921 ns/iter (+/- 45,453)
test mix_tushushu ... bench: 1,519,876 ns/iter (+/- 4,872)
test mix_twice ... bench: 1,597,130 ns/iter (+/- 11,068)
It seems your implementation performs best in most cases. You could go further and start mixing implementations, i.e. run twice
until its HashMap<&str, usize>
gets to a certain size, switch to your implementation. Since this problem appears in many places (e.g. also in sql databases, and those people love optimizing things to death), somebody probably has written a paper about the best method for it somewhere.