🔖

[Feature #8421] Enumerable#find_map を追加する提案

2024/03/22に公開

[Feature #8421] add Enumerable#find_map and Enumerable#find_all_map

  • #find のブロックの戻り値がそのままメソッドの戻り値となるような Enumerable#find_map を追加する提案
  • イメージ以下のような感じ
# user.lazy.filter_map{ _1.profile }.first と同じような感じ
result = users.find_map { _1.profile }
  • これ自体は11年前にできたチケットなんですが、暫くユースケースが提示されていなくて特に進展はなかったんですが、最近以下のようなユースケースが投稿されていました
# 特定の条件に当てはまったときに任意の値を返したい例
# Option 1
def identifier(emails, pattern: /\Ausername\+(?<identifier>[a-z|0-9]+)@domain\.com\z/i)
  result = nil
  emails.each do |email|
    if matches = pattern.match(email)
      result = matches[:identifier]
      break
    end
  end
  result
end

# Option 2
def identifier(emails, pattern: /\Ausername\+(?<identifier>[a-z|0-9]+)@domain\.com\z/i)
  matches = nil
  matches[:identifier] if emails.find { |email| matches = pattern.match(email) }
end
def find_map(collection, &block)
  result = nil
  collection.each do |item|
    break if result = yield(item)
  end
  result
end

def identifier(emails, pattern: /\Ausername\+(?<identifier>[a-z|0-9]+)@domain\.com\z/i)
  # 条件を書きつつ、任意の値を返すような処理になる
  find_map(emails) do |email|
    (matches = pattern.match(email)) && matches[:identifier]
  end
end
# proposal:
find_map(emails) do |email|
  (matches = pattern.match(email)) && matches[:identifier]
end

# break を使って任意のタイミングでブロックを抜けて、任意の値を返す
emails.find { |email| match = pattern.match(email) and break match[:identifier] }
# => "thecode"
emails.find{ pattern.match(it) }&.then{ it[:identifier] }
  • いろいろと解決方法がありますねー
GitHubで編集を提案

Discussion