summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-07-20 08:39:12 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-07-20 08:39:12 +0000
commit42c6a5137e46b885ab28b267f85c0ddc8d49b195 (patch)
tree507dc795b1f2a1420947e6b6be193ad0bbd6c496
parentf14d64638a461ff660d16b42ae827b46a0cec91b (diff)
enum.c: Enumerable#uniq
* enum.c (enum_uniq): new method Enumerable#uniq. [Feature #11090] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55709 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog5
-rw-r--r--enum.c35
-rw-r--r--test/ruby/test_enum.rb15
3 files changed, 55 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index f6834c8f13d..1baba4f7d04 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Wed Jul 20 17:39:11 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enum.c (enum_uniq): new method Enumerable#uniq.
+ [Feature #11090]
+
Wed Jul 20 17:35:23 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
* hash.c (rb_hash_add_new_element): add new element or do nothing
diff --git a/enum.c b/enum.c
index b62f7c3f37f..fb1150a8a48 100644
--- a/enum.c
+++ b/enum.c
@@ -3793,6 +3793,40 @@ enum_sum(int argc, VALUE* argv, VALUE obj)
}
}
+static VALUE
+uniq_func(RB_BLOCK_CALL_FUNC_ARGLIST(i, hash))
+{
+ rb_hash_add_new_element(hash, i, i);
+ return Qnil;
+}
+
+static VALUE
+uniq_iter(RB_BLOCK_CALL_FUNC_ARGLIST(i, hash))
+{
+ rb_hash_add_new_element(hash, rb_yield_values2(argc, argv), i);
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * enum.uniq -> new_ary
+ * enum.uniq { |item| ... } -> new_ary
+ */
+
+static VALUE
+enum_uniq(VALUE obj)
+{
+ VALUE hash, ret;
+ rb_block_call_func *const func =
+ rb_block_given_p() ? uniq_iter : uniq_func;
+
+ hash = rb_obj_hide(rb_hash_new());
+ rb_block_call(obj, id_each, 0, 0, func, hash);
+ ret = rb_hash_values(hash);
+ rb_hash_clear(hash);
+ return ret;
+}
+
/*
* The <code>Enumerable</code> mixin provides collection classes with
* several traversal and searching methods, and with the ability to
@@ -3866,6 +3900,7 @@ Init_Enumerable(void)
rb_define_method(rb_mEnumerable, "slice_when", enum_slice_when, 0);
rb_define_method(rb_mEnumerable, "chunk_while", enum_chunk_while, 0);
rb_define_method(rb_mEnumerable, "sum", enum_sum, -1);
+ rb_define_method(rb_mEnumerable, "uniq", enum_uniq, 0);
id_next = rb_intern("next");
id_call = rb_intern("call");
diff --git a/test/ruby/test_enum.rb b/test/ruby/test_enum.rb
index df75a80c503..d2403dd1a1e 100644
--- a/test/ruby/test_enum.rb
+++ b/test/ruby/test_enum.rb
@@ -921,4 +921,19 @@ class TestEnumerable < Test::Unit::TestCase
assert_int_equal(2, (2..2).sum)
assert_int_equal(42, (2...2).sum(42))
end
+
+ def test_uniq
+ src = [1, 1, 1, 1, 2, 2, 3, 4, 5, 6]
+ assert_equal([1, 2, 3, 4, 5, 6], src.uniq.to_a)
+ olimpics = {
+ 1896 => 'Athens',
+ 1900 => 'Paris',
+ 1904 => 'Chikago',
+ 1906 => 'Athens',
+ 1908 => 'Rome',
+ }
+ assert_equal([[1896, "Athens"], [1900, "Paris"], [1904, "Chikago"], [1908, "Rome"]],
+ olimpics.uniq{|k,v| v})
+ assert_equal([1, 2, 3, 4, 5, 10], (1..100).uniq{|x| (x**2) % 10 }.first(6))
+ end
end