如何在 Ruby 中迭代哈希并获取特定输出?

229

我希望能够在迭代Ruby哈希表时得到特定的输出。

以下是我想要迭代的哈希表:

hash = {
  1 => ['a', 'b'], 
  2 => ['c'], 
  3 => ['d', 'e', 'f', 'g'], 
  4 => ['h']
}

这是我想要获得的输出:

1-----

a

b

2-----

c

3-----

d 

e

f

g

4-----

h

在Ruby中,如何使用我的Hash来获得这样的输出?


3
如果您正在迭代哈希并期望它是有序的,那么您可能需要使用其他类型的集合。 - Allen Rice
我可以将哈希值作为单选按钮选项传递吗? - sts
将哈希传递为单选按钮选项... 但是对于第一个选项,我得到了单选按钮,而对于其他值,我没有得到它。 - sts
1
@Allen:在Ruby 1.9中,哈希是有序的。如果你使用的是Ruby <1.9,Rails还提供了一个OrderedHash(只在必要时使用)。请参阅http://www.culann.com/2008/01/rails-goodies-activesupportorderedhash。 - James A. Rosen
6个回答

342
hash.each do |key, array|
  puts "#{key}-----"
  puts array
end

关于需要添加的顺序,需要说明的是,在1.8中,项目将以随机顺序迭代(实际上是按照Fixnum哈希函数定义的顺序),而在1.9中,它将按字面顺序迭代。


2
如果key在任何地方都没有被使用,我们该怎么办?我们需要在key的位置上放一个?吗?例如:|?, array|,这是有效的语法吗? - huzefa biyawarwala
1
@huzefabiyawarwala,不,?在Ruby中不是一个有效的变量名。你可以使用_,但你不一定需要这样做。 - sepp2k
我的意思是,如果我们使用|k,v|来迭代哈希表,但在循环内部的逻辑实现中我们不使用k,那么有没有办法像这样编写:|_, v| - huzefa biyawarwala
2
@huzefabiyawarwala 是的,你可以写成 |_, v| - sepp2k
1
为什么要使用变量名数组而不是v或value? - jrhicks
1
@jrhicks 因为 OP 有一个值为数组的哈希表。 - Radon Rosborough

92

遍历哈希表最基本的方法如下:

hash.each do |key, value|
  puts key
  puts value
end

是的,这很有道理。为什么@sepp2k的答案在键上有一个#{}? - committedandroider
哦,不用在意了。我看到这是关于字符串插值的。 - committedandroider

50
hash.keys.sort.each do |key|
  puts "#{key}-----"
  hash[key].each { |val| puts val }
end

18

在哈希上调用sort会将其转换为嵌套数组,然后按键排序,所以你只需要这样做:

puts h.sort.map {|k,v| ["#{k}----"] + v}

如果您实际上不需要 "----" 部分,它可以简化为:

puts h.sort

哈希键是数字,所以'[k + "----"]'会引发TypeError(字符串无法强制转换为Fixnum)。你需要使用'[k.to_s + "----"]'。 - glenn jackman
足够正确。我在我的测试版本中有字母。使用更好的"#{k}----"进行修复。 - glenn mcdonald

14

我的一行解决方案:

hash.each { |key, array| puts "#{key}-----", array }

我认为这很容易阅读。


1
你还可以 改进 Hash::each 方法,使其支持递归枚举。这是我带有枚举器支持的Hash::each(即Hash::each_pair) 的版本:
module HashRecursive
    refine Hash do
        def each(recursive=false, &block)
            if recursive
                Enumerator.new do |yielder|
                    self.map do |key, value|
                        value.each(recursive=true).map{ |key_next, value_next| yielder << [[key, key_next].flatten, value_next] } if value.is_a?(Hash)
                        yielder << [[key], value]
                    end
                end.entries.each(&block)
            else
                super(&block)
            end
        end
        alias_method(:each_pair, :each)
    end
end

using HashRecursive

以下是使用 Hash::each 的示例,包括使用和不使用 recursive 标志:

注意:请保留 HTML 标签,但需使翻译内容更加通俗易懂。

hash = {
    :a => {
        :b => {
            :c => 1,
            :d => [2, 3, 4]
        },
        :e => 5
    },
    :f => 6
}

p hash.each, hash.each {}, hash.each.size
# #<Enumerator: {:a=>{:b=>{:c=>1, :d=>[2, 3, 4]}, :e=>5}, :f=>6}:each>
# {:a=>{:b=>{:c=>1, :d=>[2, 3, 4]}, :e=>5}, :f=>6}
# 2

p hash.each(true), hash.each(true) {}, hash.each(true).size
# #<Enumerator: [[[:a, :b, :c], 1], [[:a, :b, :d], [2, 3, 4]], [[:a, :b], {:c=>1, :d=>[2, 3, 4]}], [[:a, :e], 5], [[:a], {:b=>{:c=>1, :d=>[2, 3, 4]}, :e=>5}], [[:f], 6]]:each>
# [[[:a, :b, :c], 1], [[:a, :b, :d], [2, 3, 4]], [[:a, :b], {:c=>1, :d=>[2, 3, 4]}], [[:a, :e], 5], [[:a], {:b=>{:c=>1, :d=>[2, 3, 4]}, :e=>5}], [[:f], 6]]
# 6

hash.each do |key, value|
    puts "#{key} => #{value}"
end
# a => {:b=>{:c=>1, :d=>[2, 3, 4]}, :e=>5}
# f => 6

hash.each(true) do |key, value|
    puts "#{key} => #{value}"
end
# [:a, :b, :c] => 1
# [:a, :b, :d] => [2, 3, 4]
# [:a, :b] => {:c=>1, :d=>[2, 3, 4]}
# [:a, :e] => 5
# [:a] => {:b=>{:c=>1, :d=>[2, 3, 4]}, :e=>5}
# [:f] => 6

hash.each_pair(recursive=true) do |key, value|
    puts "#{key} => #{value}" unless value.is_a?(Hash)
end
# [:a, :b, :c] => 1
# [:a, :b, :d] => [2, 3, 4]
# [:a, :e] => 5
# [:f] => 6

这是问题本身的一个例子:
hash = {
    1   =>  ["a", "b"], 
    2   =>  ["c"], 
    3   =>  ["a", "d", "f", "g"], 
    4   =>  ["q"]
}

hash.each(recursive=false) do |key, value|
    puts "#{key} => #{value}"
end
# 1 => ["a", "b"]
# 2 => ["c"]
# 3 => ["a", "d", "f", "g"]
# 4 => ["q"]

请查看我对Hash::merge(Hash::merge!)的递归版本这里


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接