Ruby 2.7 — Enumerable#tally

聖誕節已通過去,2.6已經發布,如今是時候無情叫賣 2.7 版本的發佈頁面,這樣咱們就能夠開始咱們有趣的「關於即將推出的功能」的年度博客傳統。git

一般這意味着另外一個 12 月的發佈,可是若是它們能在今年年初合併到主幹,則有一些方法例子能夠更早的製做。github

此次咱們有了新的方法 Enumerable#tallyruby

簡單版

tally 計數:app

[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:ui

%w(foo foo bar foo baz foo).map { |s| s[0] }.tally
=> {「f」 => 4, 「b」 => 2}

目前正在討論接受此功能,這將產生上述語法:3d

%w(foo foo bar foo baz foo).tally_by { |s| s[0] }
=> {「f」 => 4, 「b」 => 2}

爲什麼使用?

若是您一直在使用 Ruby,那麼您可能已經使用相似其中一些代碼來作 tally 相似的上述事情:code

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 語言中縮寫很是常見的方言,也是一種很是受歡迎的方法。orm

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 回來的車上,咱們(我本身,DavidStephanieShannon)正在討論可能備用的名稱,試圖看看該函數是否能夠有不一樣的名字。

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 從這裏走出去。

相關文章
相關標籤/搜索