mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Adding Enumerable#filter_map
[Feature #15323] Closes: https://github.com/ruby/ruby/pull/2017
This commit is contained in:
parent
1ccc2eeba0
commit
0acbdd1ed0
4 changed files with 78 additions and 1 deletions
41
enum.c
41
enum.c
|
@ -452,6 +452,46 @@ enum_find_all(VALUE obj)
|
||||||
return ary;
|
return ary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
filter_map_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
|
||||||
|
{
|
||||||
|
i = rb_yield_values2(argc, argv);
|
||||||
|
|
||||||
|
if (RTEST(i)) {
|
||||||
|
rb_ary_push(ary, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* enum.filter_map { |obj| block } -> array
|
||||||
|
* enum.filter_map -> an_enumerator
|
||||||
|
*
|
||||||
|
* Returns a new array containing the truthy results (everything except
|
||||||
|
* +false+ or +nil+) of running the +block+ for every element in +enum+.
|
||||||
|
*
|
||||||
|
* If no block is given, an Enumerator is returned instead.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* (1..10).filter_map { |i| i * 2 if i.even? } #=> [4, 8, 12, 16, 20]
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static VALUE
|
||||||
|
enum_filter_map(VALUE obj)
|
||||||
|
{
|
||||||
|
VALUE ary;
|
||||||
|
|
||||||
|
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
|
||||||
|
|
||||||
|
ary = rb_ary_new();
|
||||||
|
rb_block_call(obj, id_each, 0, 0, filter_map_i, ary);
|
||||||
|
|
||||||
|
return ary;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
reject_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
|
reject_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
|
||||||
{
|
{
|
||||||
|
@ -4108,6 +4148,7 @@ Init_Enumerable(void)
|
||||||
rb_define_method(rb_mEnumerable, "find_all", enum_find_all, 0);
|
rb_define_method(rb_mEnumerable, "find_all", enum_find_all, 0);
|
||||||
rb_define_method(rb_mEnumerable, "select", enum_find_all, 0);
|
rb_define_method(rb_mEnumerable, "select", enum_find_all, 0);
|
||||||
rb_define_method(rb_mEnumerable, "filter", enum_find_all, 0);
|
rb_define_method(rb_mEnumerable, "filter", enum_find_all, 0);
|
||||||
|
rb_define_method(rb_mEnumerable, "filter_map", enum_filter_map, 0);
|
||||||
rb_define_method(rb_mEnumerable, "reject", enum_reject, 0);
|
rb_define_method(rb_mEnumerable, "reject", enum_reject, 0);
|
||||||
rb_define_method(rb_mEnumerable, "collect", enum_collect, 0);
|
rb_define_method(rb_mEnumerable, "collect", enum_collect, 0);
|
||||||
rb_define_method(rb_mEnumerable, "map", enum_collect, 0);
|
rb_define_method(rb_mEnumerable, "map", enum_collect, 0);
|
||||||
|
|
26
spec/ruby/core/enumerable/filter_map_spec.rb
Normal file
26
spec/ruby/core/enumerable/filter_map_spec.rb
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
require_relative '../../spec_helper'
|
||||||
|
require_relative 'fixtures/classes'
|
||||||
|
|
||||||
|
ruby_version_is '2.7' do
|
||||||
|
describe 'Enumerable#filter_map' do
|
||||||
|
before :each do
|
||||||
|
@numerous = EnumerableSpecs::Numerous.new(*(1..8).to_a)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns an empty array if there are no elements' do
|
||||||
|
EnumerableSpecs::Empty.new.filter_map { true }.should == []
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns an array with truthy results of passing each element to block' do
|
||||||
|
@numerous.filter_map { |i| i * 2 if i.even? }.should == [4, 8, 12, 16]
|
||||||
|
@numerous.filter_map { |i| i * 2 }.should == [2, 4, 6, 8, 10, 12, 14, 16]
|
||||||
|
@numerous.filter_map { 0 }.should == [0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
|
@numerous.filter_map { false }.should == []
|
||||||
|
@numerous.filter_map { nil }.should == []
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns an enumerator when no block given' do
|
||||||
|
@numerous.filter_map.should be_an_instance_of(Enumerator)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1135,4 +1135,14 @@ class TestEnumerable < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
assert_equal [1, 2, 3, 4, 5], (1..5).sort_by{|e| klass.new e}
|
assert_equal [1, 2, 3, 4, 5], (1..5).sort_by{|e| klass.new e}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_filter_map
|
||||||
|
@obj = (1..8).to_a
|
||||||
|
assert_equal([4, 8, 12, 16], @obj.filter_map { |i| i * 2 if i.even? })
|
||||||
|
assert_equal([2, 4, 6, 8, 10, 12, 14, 16], @obj.filter_map { |i| i * 2 })
|
||||||
|
assert_equal([0, 0, 0, 0, 0, 0, 0, 0], @obj.filter_map { 0 })
|
||||||
|
assert_equal([], @obj.filter_map { false })
|
||||||
|
assert_equal([], @obj.filter_map { nil })
|
||||||
|
assert_instance_of(Enumerator, @obj.filter_map)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -542,7 +542,7 @@ class TestEnumerator < Test::Unit::TestCase
|
||||||
|
|
||||||
def test_size_for_enum_created_from_enumerable
|
def test_size_for_enum_created_from_enumerable
|
||||||
%i[find_all reject map flat_map partition group_by sort_by min_by max_by
|
%i[find_all reject map flat_map partition group_by sort_by min_by max_by
|
||||||
minmax_by each_with_index reverse_each each_entry].each do |method|
|
minmax_by each_with_index reverse_each each_entry filter_map].each do |method|
|
||||||
assert_equal nil, @obj.send(method).size
|
assert_equal nil, @obj.send(method).size
|
||||||
assert_equal 42, @sized.send(method).size
|
assert_equal 42, @sized.send(method).size
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue