diff --git a/README.md b/README.md
index cecf3ce..2da2daf 100644
--- a/README.md
+++ b/README.md
@@ -893,6 +893,30 @@ Comparison:
Hash#values.include?: 62052.8 i/s - 1.15x slower
```
+##### `Hash#values.compact` instead of `Hash#values.select` or `Hash#select.values` (to get non-nil values) [code](code/hash/select-values-vs-values-select-vs-values-compact.rb)
+
+> To collect the non-nil values of a hash, `Hash#select { |_k, v| v }.values` allocates an intermediate hash before extracting its values;
+> `Hash#values.select { |v| v }` skips the intermediate hash but still runs a block per element;
+> `Hash#values.compact` drops the nils in C without a Ruby-level block, which is fastest.
+
+```
+$ ruby -v code/hash/select-values-vs-values-select-vs-values-compact.rb
+ruby 4.0.0 (2025-12-25 revision 553f1675f3) +PRISM [arm64-darwin25]
+Warming up --------------------------------------
+ Hash#select.values 2.887k i/100ms
+ Hash#values.select 3.526k i/100ms
+ Hash#values.compact 57.606k i/100ms
+Calculating -------------------------------------
+ Hash#select.values 29.102k (± 1.3%) i/s (34.36 μs/i) - 147.237k in 5.060206s
+ Hash#values.select 35.490k (± 0.7%) i/s (28.18 μs/i) - 179.826k in 5.067223s
+ Hash#values.compact 580.469k (± 4.2%) i/s (1.72 μs/i) - 2.938M in 5.070648s
+
+Comparison:
+ Hash#values.compact: 580468.7 i/s
+ Hash#values.select: 35489.9 i/s - 16.36x slower
+ Hash#select.values: 29101.7 i/s - 19.95x slower
+```
+
##### `Hash#merge!` vs `Hash#[]=` [code](code/hash/merge-bang-vs-\[\]=.rb)
```
diff --git a/code/hash/select-values-vs-values-select-vs-values-compact.rb b/code/hash/select-values-vs-values-select-vs-values-compact.rb
new file mode 100644
index 0000000..91d3688
--- /dev/null
+++ b/code/hash/select-values-vs-values-select-vs-values-compact.rb
@@ -0,0 +1,29 @@
+require "benchmark/ips"
+
+# Build a hash where roughly half the values are nil, so every approach
+# below returns the same result: the non-nil values.
+ARRAY = Array.new(1000) { Random.rand }
+HASH = Hash[ARRAY.map { |k| [k, k < 0.5 ? k : nil] }]
+
+def select_values
+ HASH.select { |_k, v| v }.values
+end
+
+def values_select
+ HASH.values.select { |v| v }
+end
+
+def values_compact
+ HASH.values.compact
+end
+
+# Sanity check: all three must return the same values.
+raise "not equivalent" unless select_values.sort == values_select.sort &&
+ values_select.sort == values_compact.sort
+
+Benchmark.ips do |x|
+ x.report("Hash#select.values") { select_values }
+ x.report("Hash#values.select") { values_select }
+ x.report("Hash#values.compact") { values_compact }
+ x.compare!
+end