如何遍历 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_"
]
}
]
另请参阅
所以,我有一个哈希数组,让我们以此为例
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_"
]
}
]