Hash背后的逻辑#Red Ruby中的排序

时间:2016-07-20 11:41:14

标签: ruby sorting

哈希可以使用Enumerable#sort方法按键排序。在内部,在C中,它被描述为:

return rb_ary_sort(enum_to_a(0, 0, obj));
  • #sort是否打算用于Hash
  • 我是否可以依赖其“收集密钥和排序”行为,或者我是否应该随时根据“按价值排序”进行更改?

2 个答案:

答案 0 :(得分:1)

简短回答

h = {:john => 18, :anne => 24, :beth => 35, :paul => 33}

按键排序

h.sort.to_h  # Output:  => {:anne=>24, :beth=>35, :john=>18, :paul=>33}

按值排序

h.sort_by {|_,v| v}.to_h  # Output:  => {:john=>18, :anne=>24, :paul=>33, :beth=>35}

sort和sort_by方法都返回数组,因此需要将结果转换回带有to_h的哈希。

答案很长(了解更多情况)

与提供自己的sort方法实现的Array类不同,Hash类使用Enumerable模块中实现的sort方法。

Array.instance_method(:sort)  # Output: => #<UnboundMethod: Array#sort>
Hash.instance_method(:sort)  # Output: => #<UnboundMethod: Hash(Enumerable)#sort>

诸如数字和字符串之类的对象,可以在比其他对象更大或更小的情况下(它们之间)进行比较,提供&lt; =&gt;。方法,也称为宇宙飞船方法。比较两个对象时,&lt; =&gt;如果第一个对象小于第二个对象(a&lt; b),则返回-1;如果它们相等(a == b)则返回0;如果第一个对象大于第二个对象(a> b),则返回1。 / p>

5 <=> 8  # Output:  => -1
5 <=> 5  # Output: => 0
8 <=> 5  # Output: => 1

大多数可比较或可排序的对象类(如Integer,Float,Time和String)包含一个名为Comparable的mixin,它提供以下比较运算符:&lt; (小于),&lt; =(小于或等于),==(相等),&gt; (大于),&gt; =(大于或等于)。这些方法使用了太空船操作员。

让我们找出哪些类包含Comparable mixin:

ObjectSpace.each_object(Class).select { |c| c.included_modules.include? Comparable }
# Output: => [Complex, Rational, Time, File::Stat, Bignum, Float, Fixnum, Integer, Numeric, Symbol, String, Gem::Version, IRB::Notifier::NoMsgNotifier, IRB::Notifier::LeveledNotifier]

比较运算符可用于所有上述类的对象,如以下示例所示。

# String
"a" < "b" # Output: => true
"a" > "b" # Output: => false

# Symbol
:a < :b  # Output: => true
:a > :b  # Output: => false

# Fixnum (subclass of Integer)
1 < 2  # Output: => true
2 >= 2  # Output: => true

# Float
1.0 < 2.0 # Output: => true
2.0 >= 2.0 # Output: => true

# Time
Time.local(2016, 5, 28) < Time.local(2016, 5, 29) # Output: => true

大多数排序操作都使用太空船(&lt; =&gt;)运算符。

答案 1 :(得分:0)

你的第一个问题不明确。如果要明确,它可能会基于意见,但没有正确的答案。

关于第二个问题,哈希将转换为带有to_a的数组,这可以保证您获得一个数组数组,其中每个子数组都有一个键和原始哈希的对应值按此顺序。你总能得到:

{:a => :b, :c => :d}.to_a # => [[:a, :b], [:c, :d]]

而不是:

{:a => :b, :c => :d}.to_a # => [[:b, :a], [:d, :c]]

然后,sort适用于结果。当排序数组数组时,它首先按子数组的第一个元素排序,即上面的:a:c,它们对应于原始散列的键,而不是值。所以你可以依靠你提到的行为。