[前][次][番号順一覧][スレッド一覧]

ruby-changes:56173

From: Nobuyoshi <ko1@a...>
Date: Fri, 21 Jun 2019 16:31:43 +0900 (JST)
Subject: [ruby-changes:56173] Nobuyoshi Nakada: 06a622b76e (trunk): Lazy filter_map

https://git.ruby-lang.org/ruby.git/commit/?id=06a622b76e

From 06a622b76e20b8996cd6d66c11ac7819a0996fae Mon Sep 17 00:00:00 2001
From: Nobuyoshi Nakada <nobu@r...>
Date: Fri, 21 Jun 2019 16:28:39 +0900
Subject: Lazy filter_map


diff --git a/enumerator.c b/enumerator.c
index 808ab67..983e14c 100644
--- a/enumerator.c
+++ b/enumerator.c
@@ -2026,6 +2026,40 @@ lazy_select(VALUE obj) https://github.com/ruby/ruby/blob/trunk/enumerator.c#L2026
     return lazy_add_method(obj, 0, 0, Qnil, Qnil, &lazy_select_funcs);
 }
 
+static VALUE
+lazy_filter_map_proc(RB_BLOCK_CALL_FUNC_ARGLIST(val, m))
+{
+    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
+    if (RTEST(result)) {
+        rb_funcall(argv[0], idLTLT, 1, result);
+    }
+    return Qnil;
+}
+
+/*
+ *  call-seq:
+ *     enum.filter_map { |obj| block } -> an_enumerator
+ *     enum.filter_map                 -> an_enumerator
+ *
+ *  Returns an enumerator which will return a new array containing the
+ *  truthy results (everything except +false+ or +nil+) of running the
+ *  +block+ for every element in +enum+.
+ *
+ *     (1..).lazy.filter_map { |i| i * 2 if i.even? }.take(5) #=> [4, 8, 12, 16, 20]
+ *
+ */
+static VALUE
+lazy_filter_map(VALUE obj)
+{
+    if (!rb_block_given_p()) {
+	rb_raise(rb_eArgError, "tried to call lazy filter_map without a block");
+    }
+
+    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
+					 lazy_filter_map_proc, 0),
+			   Qnil, 0);
+}
+
 static struct MEMO *
 lazy_reject_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
 {
@@ -3555,6 +3589,7 @@ InitVM_Enumerator(void) https://github.com/ruby/ruby/blob/trunk/enumerator.c#L3589
     rb_define_method(rb_cLazy, "select", lazy_select, 0);
     rb_define_method(rb_cLazy, "find_all", lazy_select, 0);
     rb_define_method(rb_cLazy, "filter", lazy_select, 0);
+    rb_define_method(rb_cLazy, "filter_map", lazy_filter_map, 0);
     rb_define_method(rb_cLazy, "reject", lazy_reject, 0);
     rb_define_method(rb_cLazy, "grep", lazy_grep, 1);
     rb_define_method(rb_cLazy, "grep_v", lazy_grep_v, 1);
diff --git a/test/ruby/test_lazy_enumerator.rb b/test/ruby/test_lazy_enumerator.rb
index d42c8d3..e76a53e 100644
--- a/test/ruby/test_lazy_enumerator.rb
+++ b/test/ruby/test_lazy_enumerator.rb
@@ -578,4 +578,13 @@ EOS https://github.com/ruby/ruby/blob/trunk/test/ruby/test_lazy_enumerator.rb#L578
     assert_equal([1, 2, 3, 4, 5, 10], u.first(6))
     assert_equal([1, 2, 3, 4, 5, 10], u.first(6))
   end
+
+  def test_filter_map
+    e = (1..Float::INFINITY).lazy.filter_map do |x|
+      raise "too big" if x > 10000
+      (x**2) % 10 if x.even?
+    end
+    assert_equal([4, 6, 6, 4, 0, 4], e.first(6))
+    assert_equal([4, 6, 6, 4, 0, 4], e.first(6))
+  end
 end
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]