Ruby 2.7 — Enumerable#tally
聖誕節已經過去,2.6已經發布,現在是時候無情叫賣 2.7 版本的釋出頁面,這樣我們就可以開始我們有趣的「關於即將推出的功能」的年度部落格傳統。
通常這意味著另一個 12 月的釋出,但是如果它們能在今年年初合併到主幹,則有一些方法例子可以更早的製作。
這次我們有了新的方法Enumerable#tally
!
簡單版
tally
計數:
[1, 1, 2].tally # => { 1 => 2, 2 => 1 } [1, 1, 2].map(&:even?).tally # => { false => 2, true => 1 }
例子
Ruby 官方測試程式碼中使用的示例:
[1, 2, 2, 3].tally # => { 1 => 1, 2 => 2, 3 => 1 }
沒有塊(Block),tally
計算 Enumerable 型別中每個元素的出現次數,如果我們將它應用於另一種型別的列表,它可能會更清楚一些:
%w(foo foo bar foo baz foo).tally => {"foo"=>4, "bar"=>1, "baz"=>1}
目前tally_by
尚未被接受到核心,因此要通過函式計算,您將首先使用 map:
%w(foo foo bar foo baz foo).map { |s| s[0] }.tally => {“f” => 4, “b” => 2}
目前正在討論 接受此功能,這將產生上述語法:
%w(foo foo bar foo baz foo).tally_by { |s| s[0] } => {“f” => 4, “b” => 2}
為何使用?
如果您一直在使用 Ruby,那麼您可能已經使用類似其中一些程式碼來做tally
類似的上述事情:
list.group_by { |v| v.something }.transform_values(&:size) list.group_by { |v| v.something }.map { |k, vs| [k, vs.size] }.to_h list.group_by { |v| v.something }.to_h { |k, vs| [k, vs.size] } list.each_with_object(Hash.new(0)) { |v, h| h[v.something] += 1 }
可能還有其他幾種變體,但這些是您可能會看到的一些更常見的變體。這是一種非常優雅的方法在 Ruby 語言中縮寫非常常見的方言,也是一種非常受歡迎的方法。
Vanilla Ruby Equivalent
這種方法有什麼作用?好吧,如果我們要在普通的 Ruby 中實現它,它可能看起來像這樣:
module Enumerable def tally_by(&function) function ||= -> v { v } each_with_object(Hash.new(0)) do |value, hash| hash[function.call(value)] += 1 end end def tally tally_by(&:itself) end end
在沒有提供函式的情況下,它會通過itself
有效統計,或者更確切地說是標識函式。
標識函式是返回給定內容的函式。如果你給它1
,它會返回1
。如果你給它true
,它會返回true
。Ruby 也在一個名為itself
的方法中使用了這個概念。
本文不會深入討論上述程式碼的作用。第五部分 “Reducing Enumerable ” 更詳細地介紹了此程式碼。
原始碼
Nobu 最近提交了一個 Ruby 核心補丁來新增這個方法:
enum.c: Enumerable#tally · ruby/ruby@673dc51
https://github.com/ruby/ruby/...
它被 Ruby 核心團隊接受,名為tally
:
Feature #11076: Enumerable method count_by - Ruby trunk - Ruby Issue Tracking System
https://bugs.ruby-lang.org/is...
Tally?
讓我們從這個詞的含義開始:
A tally is a record of amounts or numbers which you keep changing and adding to as the activity which affects it progresses.
https://www.collinsdictionary...
這個名字來自哪裡?最初提出來的名字是count_by
,但名稱被拒絕,因為它和count
方法有不同的返回型別和行為。
在從 Tahoe 地區和RailsCamp West 回來的車上,我們(我自己,David ,Stephanie 和Shannon )正在討論可能備用的名稱,試圖看看該函式是否可以有不同的名字。
David
並正式提出tally
並建議。看起來取名字卡住了,程式碼已合併到主幹中。
現在我在幾個會議上發表了演講,並決定在我的 RubyConf 演講中的一節中用tally_by
替代count_by
。文字版在這裡:
Reducing Enumerable — Part Five: Cerulean, Master of Tally By
https://medium.com/@baweaver/...
只是一些有趣的背景故事。
Wrapping Up
2.7 正在路上,讓我們看看它會帶來什麼!我很期待看到 Ruby 從這裡走出去。