如何遍历 Ruby 中的哈希数组以将每个成员与数组中的以下成员进行比较?

How to iterate over an array of hashes in Ruby to compare each member with the following members in the array?

所以,我有一个哈希数组,让我们以此为例

arr = [
  {:series=>"GOT", :rating=>"Good", :type=>"Fantasy"},
  {:series=>"BB", :rating=>"Great", :type=>"Crime"},
  {:series=>"E", :rating=>"Poor", :type=>"Drama"}
]

我试图遍历这个数组,以便我可以将每个成员与所有后续成员进行比较。

例如哈希 1 与哈希 2 和哈希 3 比较,哈希 2 与哈希 3 比较

实际比较函数我已经写好了:

output = (data[X].keys & data[Y].keys).select { |k| data[X][k] == data[Y][k] }

X 是当前数组,Y 是我们要比较的下一个元素。

编辑

这是我目前所知道的

for i in 0..data.length
  for j in i..data.length
    # puts data[j + 1]
    output = (data[j].keys & data[j+1].keys).select { |k| data[j][k] == data[j+1][k] }
    puts data[j]
    puts data[j+1]
    puts output
  end
  puts "*****"
end

我想要的输出是打印我们正在比较的散列和另一个散列,以及它们共享值的键。

例如这个数组:

{:series=>"GOT", :rating=>"Great", :type=>"Fantasy"}
{:series=>"BB", :rating=>"Great", :type=>"Crime"}

应该打印这个:

{:series=>"GOT", :rating=>"Great", :type=>"Fantasy"}
{:series=>"BB", :rating=>"Great", :type=>"Crime"}
rating

如果key为nil,则不进行比较。我认为这就是为什么当 运行 上面的代码时我也会收到此错误:

Traceback (most recent call last):
        4: from match_users.rb:18:in `<main>'
        3: from match_users.rb:18:in `each'
        2: from match_users.rb:19:in `block in <main>'
        1: from match_users.rb:19:in `each'
match_users.rb:21:in `block (2 levels) in <main>': undefined method `keys' for nil:NilClass (NoMethodError)

请注意,您没有在循环中使用“i”,这看起来像是一个错误。此外,您的索引“j+1”离开数组的末尾,导致访问 nil 元素。实际上,即使是“j”也离开了数组的末尾。数组从 0...length-1 开始访问,而“0..data.length”将访问索引 data.length 处的元素。我猜你的意思更像是:

for i in 0..data.length-2
  for j in i+1..data.length-1
    output = (data[i].keys & data[j].keys).select { |k| data[i][k] == data[j][k] }
  end
end

创建一个 Iterable Collection

首先,您发布的数据不是有效的 Ruby 哈希数组;它只是 Hash objects 的顺序列表,因此您不能对其进行迭代。您需要首先将 Hash objects 包装成可迭代的东西,例如数组。这是一个例子:

titles = 
  [{:series=>"GOT", :rating=>"Good", :type=>"Fantasy"},                                                                                                                                  
   {:series=>"BB", :rating=>"Great", :type=>"Crime"},
   {:series=>"E", :rating=>"Poor", :type=>"Drama"}]

连续元素的相对比较

现在你有一个可迭代的 collection,你可以使用 Enumerable#each_cons(它已经混合到 Ruby 的核心中的数组中)来迭代每个顺序对哈希 objects。出于演示目的,我选择将相对比较存储为每个标题中数组的一部分。例如,使用存储在 titles 中的散列数组 objects 如上:

STAR_MAPPINGS = {'great' => 5, 'good' => 4, 'fair' => 2,
                 'poor' => 1, 'unwatchable' => 0}.freeze

COMPARISON_MAP = {
  -1 => 'is worse than',
   0  => 'the same as',
   1  => 'is better than'
}.freeze

def compare_ratings_for title_1, title_2
  fmt = '_%s_ %s _%s_'
  series_1, series_2 = title_1[:series], title_2[:series]
  ratings_1, ratings_2 = 
    STAR_MAPPINGS[title_1[:rating].downcase],
    STAR_MAPPINGS[title_2[:rating].downcase]
  comparison_str = COMPARISON_MAP[ratings_1 <=> ratings_2]
  format fmt, series_1, comparison_str, series_2
end

titles.each_cons(2).each do |h1, h2|
  # Array#| return an ordered, deduplicated union of keys
  matching_keys = (h1.keys | h2.keys).flatten.uniq
  next if matching_keys.none?

  # perform whatever comparisons you want here; this example
  # compares ratings by assigning stars to each rating
  h1[:comparisons] =
    h1.fetch(:comparisons, []) << compare_ratings_for(h1, h2)
  h2[:comparisons] =
    h2.fetch(:comparisons, []) << compare_ratings_for(h2, h1)
end

titles

titles 变量现在包含 returns 以下数据:

[{:series=>"GOT", :rating=>"Good", :type=>"Fantasy", :comparisons=>["_GOT_ is worse than _BB_"]},
 {:series=>"BB", :rating=>"Great", :type=>"Crime", :comparisons=>["_BB_ is better than _GOT_", "_BB_ is better than _E_"]},
 {:series=>"E", :rating=>"Poor", :type=>"Drama", :comparisons=>["_E_ is worse than _BB_"]}]

这里又是相同的数据,但这次 标题 是 pretty-printed 和 amazing_print 以提高可读性:

[
  {                                                                                     
         :series => "GOT",                                                              
         :rating => "Good",                                                             
           :type => "Fantasy",                                                          
    :comparisons => [                                                                   
      "_GOT_ is worse than _BB_"                                                        
    ]                                                                                   
  },                                                                                    
  {                                                                                     
         :series => "BB",                                                               
         :rating => "Great",                                                            
           :type => "Crime",
    :comparisons => [
      "_BB_ is better than _GOT_",
      "_BB_ is better than _E_"
    ]
  },
  {
         :series => "E",
         :rating => "Poor",
           :type => "Drama",
    :comparisons => [
      "_E_ is worse than _BB_"
    ]
  }
]

另请参阅