Enumerable的group_by是否保留了Enumerable的顺序?

Enumerable#group_by是否保留每个值中的原始顺序? 当我得到这个:

 [1, 2, 3, 4, 5].group_by{|i| i % 2} # => {1=>[1, 3, 5], 0=>[2, 4]} 

是否保证,例如,数组[1, 3, 5]按此顺序包含元素而不是,例如[3, 1, 5]

有关于这一点的描述吗?

我没有提到键10之间的顺序。 这是一个不同的问题。

是, Enumerable#group_by保留输入顺序。

以下是MRI中该方法的实现,来自https://github.com/ruby/ruby/blob/trunk/enum.c :

 static VALUE enum_group_by(VALUE obj) { VALUE hash; RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size); hash = rb_hash_new(); rb_block_call(obj, id_each, 0, 0, group_by_i, hash); OBJ_INFECT(hash, obj); return hash; } static VALUE group_by_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, hash)) { VALUE group; VALUE values; ENUM_WANT_SVALUE(); group = rb_yield(i); values = rb_hash_aref(hash, group); if (!RB_TYPE_P(values, T_ARRAY)) { values = rb_ary_new3(1, i); rb_hash_aset(hash, group, values); } else { rb_ary_push(values, i); } return Qnil; } 

enum_group_by调用每个数组( obj )元素上的group_by_igroup_by_i在第一次遇到一个组时创建一个单元素数组( rb_ary_new3(1, i) ),然后推送到该数组( rb_ary_push(values, i) )。 因此保留了输入顺序。

此外,RubySpec需要它。 来自https://github.com/rubyspec/rubyspec/blob/master/core/enumerable/group_by_spec.rb :

 it "returns a hash with values grouped according to the block" do e = EnumerableSpecs::Numerous.new("foo", "bar", "baz") h = e.group_by { |word| word[0..0].to_sym } h.should == { :f => ["foo"], :b => ["bar", "baz"]} end 

更具体地说, Enumerable调用each因此它取决于each实现的方式以及each是否按原始顺序生成元素:

 class ReverseArray < Array def each(&block) reverse_each(&block) end end array = ReverseArray.new([1,2,3,4]) #=> [1, 2, 3, 4] array.group_by { |i| i % 2 } #=> {0=>[4, 2], 1=>[3, 1]}