Project

General

Profile

Actions

Feature #1154

closed

{Array,Enumerable}#uniq_by, #uniq_by!

Added by nobu (Nobuyoshi Nakada) about 16 years ago. Updated about 14 years ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-dev:37998]

Description

=begin
なかだです。

ブロックの値にしたがって一意のものを選ぶ、Array#uniq_byというの
はどうでしょうか。


Index: array.c

--- array.c (revision 22100)
+++ array.c (working copy)
@@ -2875,13 +2875,40 @@ ary_add_hash(VALUE hash, VALUE ary)
}

-static VALUE
-ary_make_hash(VALUE ary)
+static inline VALUE
+ary_tmp_hash_new(void)
{
VALUE hash = rb_hash_new();

  RBASIC(hash)->klass = 0;
  • return hash;
    +}

+static VALUE
+ary_make_hash(VALUE ary)
+{

  • VALUE hash = ary_tmp_hash_new();
    return ary_add_hash(hash, ary);
    }

+static VALUE
+ary_add_hash_by(VALUE hash, VALUE ary)
+{

  • long i;
  • for (i = 0; i < RARRAY_LEN(ary); ++i) {
  • VALUE v = rb_ary_elt(ary, i), k = rb_yield(v);
  • if (rb_hash_lookup2(hash, k, Qundef) == Qundef) {
  •  rb_hash_aset(hash, k, v);
    
  • }
  • }
  • return hash;
    +}

+static VALUE
+ary_make_hash_by(VALUE ary)
+{

  • VALUE hash = ary_tmp_hash_new();
  • return ary_add_hash_by(hash, ary);
    +}

static inline void
ary_recycle_hash(VALUE hash)
@@ -3063,4 +3090,43 @@ rb_ary_uniq(VALUE ary)
}

+static int
+push_value(st_data_t key, st_data_t val, st_data_t ary)
+{

  • rb_ary_push((VALUE)ary, (VALUE)val);
  • return ST_DELETE;
    +}

+static VALUE
+rb_ary_uniq_by_bang(VALUE ary)
+{

  • VALUE hash;
  • long size;
  • RETURN_ENUMERATOR(ary, 0, 0);
  • hash = ary_make_hash_by(ary);
  • size = RHASH_SIZE(hash);
  • if (RARRAY_LEN(ary) == size) return Qnil;
  • ary_resize_capa(ary, size);
  • ARY_SET_LEN(ary, 0);
  • st_foreach(RHASH_TBL(hash), push_value, ary);
  • ary_recycle_hash(hash);
  • return ary;
    +}

+static VALUE
+rb_ary_uniq_by(VALUE ary)
+{

  • VALUE hash;
  • long size;
  • RETURN_ENUMERATOR(ary, 0, 0);
  • hash = ary_make_hash_by(ary);
  • size = RHASH_SIZE(hash);
  • ary = ary_new(rb_obj_class(ary), size);
  • st_foreach(RHASH_TBL(hash), push_value, ary);
  • ary_recycle_hash(hash);
  • return ary;
    +}

/*

  • call-seq:
    @@ -3920,4 +3986,6 @@ Init_Array(void)
    rb_define_method(rb_cArray, "uniq", rb_ary_uniq, 0);
    rb_define_method(rb_cArray, "uniq!", rb_ary_uniq_bang, 0);
  • rb_define_method(rb_cArray, "uniq_by", rb_ary_uniq_by, 0);
  • rb_define_method(rb_cArray, "uniq_by!", rb_ary_uniq_by_bang, 0);
    rb_define_method(rb_cArray, "compact", rb_ary_compact, 0);
    rb_define_method(rb_cArray, "compact!", rb_ary_compact_bang, 0);
    Index: enum.c
    ===================================================================
    --- enum.c (revision 22100)
    +++ enum.c (working copy)
    @@ -1794,4 +1794,29 @@ enum_cycle(int argc, VALUE *argv, VALUE
    }

+static VALUE
+enum_uniq_by_i(VALUE i, VALUE hash, int argc, VALUE *argv)
+{

  • return rb_hash_aset(hash, rb_yield_values(argc, argv), i);
    +}

+static int
+push_value(st_data_t key, st_data_t val, st_data_t ary)
+{

  • rb_ary_push((VALUE)ary, (VALUE)val);
  • return ST_DELETE;
    +}

+static VALUE
+enum_uniq_by(VALUE obj)
+{

  • VALUE hash = rb_hash_new(), uniq;
  • RBASIC(hash)->klass = 0;
  • rb_block_call(obj, id_each, 0, 0, enum_uniq_by_i, hash);
  • uniq = rb_ary_new2(RHASH_SIZE(hash));
  • st_foreach(RHASH_TBL(hash), push_value, uniq);
  • return uniq;
    +}

/*

  • The Enumerable mixin provides collection classes with
    @@ -1853,4 +1878,5 @@ Init_Enumerable(void)
    rb_define_method(rb_mEnumerable, "drop_while", enum_drop_while, 0);
    rb_define_method(rb_mEnumerable, "cycle", enum_cycle, -1);
  • rb_define_method(rb_mEnumerable, "uniq_by", enum_uniq_by, 0);

    id_eqq = rb_intern("===");

--
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
中田 伸悦
=end

Actions #1

Updated by matz (Yukihiro Matsumoto) about 16 years ago

=begin
まつもと ゆきひろです

In message "Re: [ruby-dev:37998] [Feature:1.9] {Array,Enumerable}#uniq_by, #uniq_by!"
on Fri, 13 Feb 2009 22:19:41 +0900, Nobuyoshi Nakada writes:

|ブロックの値にしたがって一意のものを選ぶ、Array#uniq_byというの
|はどうでしょうか。

現在ブロックを受け付けていないのですから、uniq_byを新規に導入
するよりも uniq{|x| f(x} で「ブロックの値に従って一意のものを
選ぶ」方が良いのではないでしょうか。sort, maxとは異なります
が、これらは元からブロックを取っていましたから。

=end

Actions #2

Updated by nobu (Nobuyoshi Nakada) about 16 years ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100

=begin
Applied in changeset r22307.
=end

Actions #3

Updated by znz (Kazuhiro NISHIYAMA) about 16 years ago

=begin
西山和広です。

At Sat, 14 Feb 2009 18:19:59 +0900,
Yukihiro Matsumoto wrote:

|ブロックの値にしたがって一意のものを選ぶ、Array#uniq_byというの
|はどうでしょうか。

現在ブロックを受け付けていないのですから、uniq_byを新規に導入
するよりも uniq{|x| f(x} で「ブロックの値に従って一意のものを
選ぶ」方が良いのではないでしょうか。sort, maxとは異なります
が、これらは元からブロックを取っていましたから。

uniq_byの方がブロックなしの時にEnumeratorが得られて便利かも
しれないと思ったのですが、どうでしょうか?

--
|ZnZ(ゼット エヌ ゼット)
|西山和広(Kazuhiro NISHIYAMA)

=end

Actions #4

Updated by matz (Yukihiro Matsumoto) about 16 years ago

=begin
まつもと ゆきひろです

In message "Re: [ruby-dev:38015] Re: [Feature:1.9] {Array,Enumerable}#uniq_by, #uniq_by!"
on Sun, 15 Feb 2009 06:59:09 +0900, Kazuhiro NISHIYAMA writes:

|uniq_byの方がブロックなしの時にEnumeratorが得られて便利かも
|しれないと思ったのですが、どうでしょうか?

ブロックなしでEnumeratorをもらってうれしい場合が思いつきませ
ん。むしろ、ブロックを渡して(配列ではなく)Enumeratorでほしい
というならわかりますが。

=end

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0