Với mã (trong C) cho Array#uniq
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;
}
Trong trường hợp tổng quát (các else
khối), nó tạo ra một hash từ mảng (mà thống nhất chìa khóa mà không cần giữ trật tự). Sau đó, nó tạo ra một mảng trống mới với kích thước phù hợp. Cuối cùng nó đi qua mảng đầu tiên và khi nó tìm thấy khóa trong băm, nó xóa khóa đó và đẩy nó vào mảng trống.
Do đó, đơn đặt hàng được lưu giữ.
Tôi muốn nói độ phức tạp là O (độ phức tạp (ary_make_hash) + N) trong thời gian, có thể là O (N)
Wow, câu trả lời tuyệt vời! – Antoine
Điều này thật tuyệt vời khi tôi có nhu cầu bảo quản thứ tự, ví dụ đầu tiên của mỗi lần xuất hiện duy nhất là encuntered.ie: {1,2,1,4,5,4,6,4} => {1,2 , 4,5,6} Vì "tính năng" này không được ghi thành tài liệu nên nó vẫn giữ nguyên? – peterk
Thứ tự chèn được giữ nguyên từ ruby 1.9 trở lên. Bộ được xây dựng dựa trên băm. Vì vậy, điều này sẽ vẫn như cũ (xem câu hỏi SO này để biết thêm thông tin https://stackoverflow.com/questions/773403/ruby-want-a-set-like-object-which-preserves-order#answer-14468621) – astreal