Skip to content

Commit 68ad9dd

Browse files
committed
Separate keys and values, and simplify benchmarks
1 parent c27969a commit 68ad9dd

File tree

4 files changed

+62
-93
lines changed

4 files changed

+62
-93
lines changed

README.md

Lines changed: 21 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -805,56 +805,43 @@ Comparison:
805805
Hash#keys.each: 869262.3 i/s - 1.21x slower
806806
```
807807

808-
#### `Hash#key?` instead of `Hash#keys.include?` and `Hash#value?` instead of `Hash#values.include?` [code](code/hash/keys-include-vs-key.rb)
808+
#### `Hash#key?` vs. `Hash#[]` vs. `Hash#keys.include?` [code](code/hash/keys-include-vs-\[\]-vs-key.rb)
809809

810810
> `Hash#keys.include?` allocates an array of keys and performs an O(n) search; <br>
811-
> `Hash#key?` performs an O(1) hash lookup without allocating a new array. <br>
812-
> `Hash#values.include?` allocates an array of values and performs an O(n) search; <br>
813-
> `Hash#value?` performs an O(n) search without allocating a new array.
811+
> `Hash#key?` performs an O(1) hash lookup without allocating a new array; <br>
812+
> `Hash#[]` performs an O(1) hash lookup as well.
814813
815814
```
816-
$ ruby -v code/hash/keys-include-vs-key.rb
815+
$ ruby -v code/hash/keys-include-vs-\[\]-vs-key.rb
817816
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin17]
818817
819818
Calculating -------------------------------------
820-
Hash#key? (key is present)
821-
5.809M (± 2.1%) i/s - 29.038M in 5.000966s
822-
Hash#keys.include? (key is present)
823-
8.914k (± 3.9%) i/s - 44.564k in 5.007900s
819+
Hash#keys.include? 8.293k (± 6.1%) i/s - 41.964k in 5.083215s
820+
Hash#[] 6.412M (± 3.1%) i/s - 32.160M in 5.020295s
821+
Hash#key? 6.616M (± 5.0%) i/s - 33.178M in 5.030955s
824822
825823
Comparison:
826-
Hash#key? (key is present): 5809154.8 i/s
827-
Hash#keys.include? (key is present): 8913.6 i/s - 651.72x slower
828-
829-
Calculating -------------------------------------
830-
Hash#key? (key is absent)
831-
7.691M (± 1.9%) i/s - 38.520M in 5.010779s
832-
Hash#keys.include? (key is absent)
833-
2.991k (± 2.1%) i/s - 15.100k in 5.051475s
824+
Hash#key?: 6615589.2 i/s
825+
Hash#[]: 6412217.3 i/s - same-ish: difference falls within error
826+
Hash#keys.include?: 8293.2 i/s - 797.71x slower
827+
```
834828

835-
Comparison:
836-
Hash#key? (key is absent): 7690551.0 i/s
837-
Hash#keys.include? (key is absent): 2990.5 i/s - 2571.62x slower
829+
##### `Hash#value?` instead of `Hash#values.include?` [code](code/hash/values-include-vs-value.rb)
838830

839-
Calculating -------------------------------------
840-
Hash#value? (value is present)
841-
14.780k (± 0.9%) i/s - 74.970k in 5.072806s
842-
Hash#values.include? (value is present)
843-
14.019k (± 4.4%) i/s - 70.533k in 5.041592s
831+
> `Hash#values.include?` allocates an array of values and performs an O(n) search; <br>
832+
> `Hash#value?` performs an O(n) search without allocating a new array.
844833
845-
Comparison:
846-
Hash#value? (value is present): 14780.1 i/s
847-
Hash#values.include? (value is present): 14019.0 i/s - 1.05x slower
834+
```
835+
$ ruby -v code/hash/values-include-vs-value.rb
836+
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin17]
848837
849838
Calculating -------------------------------------
850-
Hash#value? (value is absent)
851-
2.640k (± 2.1%) i/s - 13.200k in 5.002081s
852-
Hash#values.include? (value is absent)
853-
2.930k (± 6.1%) i/s - 14.994k in 5.144089s
839+
Hash#values.include? 23.187k (± 4.3%) i/s - 117.720k in 5.086976s
840+
Hash#value? 38.395k (± 1.0%) i/s - 194.361k in 5.062696s
854841
855842
Comparison:
856-
Hash#values.include? (value is absent): 2930.0 i/s
857-
Hash#value? (value is absent): 2640.1 i/s - 1.11x slower
843+
Hash#value?: 38395.0 i/s
844+
Hash#values.include?: 23186.8 i/s - 1.66x slower
858845
```
859846

860847
##### `Hash#merge!` vs `Hash#[]=` [code](code/hash/merge-bang-vs-\[\]=.rb)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
require "benchmark/ips"
2+
3+
HASH = Hash[*("a".."zzz").to_a.shuffle]
4+
KEY = "zz"
5+
6+
def key_fast
7+
HASH.key? KEY
8+
end
9+
10+
def key_resolve
11+
!!HASH[KEY]
12+
end
13+
14+
def key_slow
15+
HASH.keys.include? KEY
16+
end
17+
18+
Benchmark.ips do |x|
19+
x.report("Hash#keys.include?") { key_slow }
20+
x.report("Hash#[]") { key_resolve }
21+
x.report("Hash#key?") { key_fast }
22+
x.compare!
23+
end

code/hash/keys-include-vs-key.rb

Lines changed: 0 additions & 59 deletions
This file was deleted.

code/hash/values-include-vs-value.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
require "benchmark/ips"
2+
3+
HASH = Hash[*("a".."zzz").to_a.shuffle]
4+
VALUE = "zz"
5+
6+
def value_fast
7+
HASH.value? VALUE
8+
end
9+
10+
def value_slow
11+
HASH.values.include? VALUE
12+
end
13+
14+
Benchmark.ips do |x|
15+
x.report("Hash#values.include?") { value_slow }
16+
x.report("Hash#value?") { value_fast }
17+
x.compare!
18+
end

0 commit comments

Comments
 (0)