8

谁能告诉我ruby内部使用哪种算法来使用Array#uniq方法从ruby数组中删除重复项?

4

5 回答 5

7

文档

static VALUE
rb_ary_uniq(VALUE ary)
{
    VALUE hash, uniq, v;
    long i;

    if (RARRAY_LEN(ary) <= 1)
        return rb_ary_dup(ary);
    if (rb_block_given_p()) {
        hash = ary_make_hash_by(ary);
        uniq = ary_new(rb_obj_class(ary), RHASH_SIZE(hash));
        st_foreach(RHASH_TBL(hash), push_value, uniq);
    }
    else {
        hash = ary_make_hash(ary);
        uniq = ary_new(rb_obj_class(ary), RHASH_SIZE(hash));
        for (i=0; i<RARRAY_LEN(ary); i++) {
            st_data_t vv = (st_data_t)(v = rb_ary_elt(ary, i));
            if (st_delete(RHASH_TBL(hash), &vv, 0)) {
                rb_ary_push(uniq, v);
            }
        }
    }
    ary_recycle_hash(hash);

    return uniq;

它具有O(N)复杂性

于 2013-01-07T17:08:42.710 回答
3

摊销 O(n),因为它在内部使用 Hash

于 2013-01-07T17:07:19.607 回答
3

这取决于您在谈论哪些“内部”。目前使用的 Ruby 实现有 7 个生产就绪,并且 Ruby 语言规范没有规定任何特定的算法。所以,这真的取决于实施。

例如,这是Rubinius 使用的实现

Rubinius.check_frozen

if block_given?
  im = Rubinius::IdentityMap.from(self, &block)
else
  im = Rubinius::IdentityMap.from(self)
end
return if im.size == size

array = im.to_array
@tuple = array.tuple
@start = array.start
@total = array.total

self

这是来自 JRuby 的

RubyHash hash = makeHash();
if (realLength == hash.size()) return makeShared();

RubyArray result = new RubyArray(context.runtime, getMetaClass(), hash.size()); 

int j = 0;
try {
    for (int i = 0; i < realLength; i++) {
        IRubyObject v = elt(i);
        if (hash.fastDelete(v)) result.values[j++] = v;
    }
} catch (ArrayIndexOutOfBoundsException aioob) {
    concurrentModification();
}
result.realLength = j;
return result;
于 2013-01-07T22:27:28.827 回答
1

It compares elements using their hash (provided by the Object#hash method) then compares hashes with Object#eql?.

来源:https ://github.com/ruby/ruby/blob/trunk/array.c#L3976

于 2013-01-07T17:11:58.567 回答
1

时间复杂度是线性时间,即 O(n),因为它使用 Hash 进行算法的内部实现。

于 2014-10-10T02:54:55.900 回答