Project

General

Profile

Feature #12080

Enumerable#first, Array#last with block

Added by rhenium (Kazuki Yamaguchi) about 3 years ago. Updated almost 3 years ago.

Status:
Open
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:<unknown>]

Description

I propose a new feature: {Enumerable,Array,Range}#first, {Array,Range}#last with block.

If no argument is passed:

  • enum.first { block } works as the same as enum.find { block }
  • ary.last { block } works as the same as ary.reverse_each.find { block }

If a integer is passed:

  • enum.first(n) { block } works as the same as enum.lazy.select { block }.first(n)
  • ary.last(n) { block } works as the same as ary.reverse_each.lazy.select { block }.first(n).reverse

Examples:

ary = [1, 2, 3, 4, 5, 6]
ary.first    { |i| i.even? } #=> 2
ary.first(2) { |i| i.even? } #=> [2, 4]

ary.last     { |i| i.odd? }  #=> 5
ary.last(2)  { |i| i.odd? }  #=> [3, 5]

Currently these methods just ignore given blocks.

ary.first { |i| i > 3 } #=> 1

I sometimes write such code:

ary = ["DEBUG: a", "WARN: b", ..., "WARN: y", "DEBUG: z"] # assume a large Array
ary.reverse_each.lazy.reject { |line| line.include?("DEBUG") }.first(10).reverse #=> returns last 10 non-debug logs

But this is redundant and not intuitive. In this case, I just want the last 10 logs which is not debug message in the original order.
With the new Array#last, I can refactor it:

ary.last(10) { |line| !line.include?("DEBUG") }

I think this represents what I want to do much more clearly.


Files

History

Updated by shyouhei (Shyouhei Urabe) almost 3 years ago

We looked at this on this month's developer meeting but I remember there was no concrete consensus for this request.

Also available in: Atom PDF