[Active Support 原始碼閱讀解析] Hash compact 以及 compact! method

Active Support 針對 Ruby 裡面許多的 Class 增加了很多方便的工具給你使用。

最近開始閱讀 Rails 的 source code ,目前先以比較簡單的部分為主軸。

今天要解析 Active Support 針對 Hash 提供的 compact 以及 compact! 這兩個 method 。

原始碼在這裡: /activesupport/lib/active_support/core_ext/hash/compact.rb

compact 以及 compact! 的用途

這兩個 method 的主要用途為:把一個 hash 當中,值為 nil 者排除。

compact 傳回的是排除 nil 的新 hash ,也就是說原來的 hash 不會更動:

hash = { a: true, b: false, c: nil}
hash.compact # => { a: true, b: false}
hash # => { a: true, b: false, c: nil}

compact! 則會直接更改原來的 hash :

hash = { a: true, b: false, c: nil}
hash.compact! # => { a: true, b: false}
hash # => { a: true, b: false}

解析原始碼

class Hash
  def compact
    self.select { |_, value| !value.nil? }
  end
  
  def compact!
    self.reject! { |_, value| value.nil? }
  end
end

原理非常簡單,只要了解 select 以及 reject! 這兩個 method 的功用就可以輕易看懂。

官方文件針對 select 的說明是:

把在 block 中返回值為 true 的所有項目集合起來、組成一個新 hash。

如下:

h = { "a" => 100, "b" => 200, "c" => 300 }
h.select {|k,v| k > "a"}  #=> {"b" => 200, "c" => 300}

而官方文件針對 reject! 的說明如下:

等同於 Hash#delete_if ,不過如果沒有更動到什麼的話會返回 nil。

看說明便可以知道 delete_if 這個 method 會把在 block 中為 true 的所有項目都刪除。例如:

h = { "a" => 100, "b" => 200, "c" => 300 }
h.delete_if {|key, value| key >= "b" }   
puts h #=> {"a"=>100}

因此簡單來說 compact 會把所有非 nil 的項目組合成一個新 hash,而 compact! 則會把原 hash 中所有為 nil 的項目刪除。

comments powered by Disqus
分享至 Facebook 分享至 Google +