我有一个数组和一个哈希:
a = [
{ :color => "blue", :name => "wind" },
{ :color => "red", :name => "fire" },
{ :color => "white", :name => "wind" },
{ :color => "yellow", :name => "wind" },
{ :color => "green", :name => nil },
{ :color => "black", :name => "snow" }
]
b = { blue: 'blue', white: 'white', red: 'red', green: 'green', black: 'black' }
我需要找到基于输入哈希的唯一名称来得到这个:
['wind', 'fire', 'snow']
我试过了:
names = a.map { |i| [i[:color], i[:name]] }
.delete_if { |key, value| value.nil? }
resultant_names = []
b.values.each do |c|
if names[c]
resultant_names << names[c]
end
end
resultant_names.uniq
我需要一个更好的方法。这个有太多的循环。
虽然你的结果对我来说没有意义(例如它失踪了雪),但这样可行
a.map(&:values).reverse.to_h.values_at(*b.values).compact.uniq
#=> ["wind","fire"]
要打破它:
a.map(&:values).reverse.to_h
#=> {"white"=>"wind", "green"=>nil, "yellow"=>"wind", "red"=>"fire", "blue"=>"wind"}
你会注意到雪已经缺失,因为当我们反转列表时,["white","wind"]
将在转换为["white","snow"]
时覆盖Hash
然后我们只收集给定颜色的值
b.values
#=> ["blue", "white", "red", "green"]
a.map(&:values).reverse.to_h.values_at(*b.values)
#=> ["wind", "wind", "fire", nil]
然后Array#compact
将删除nil
元素和Array#uniq
将使列表独特。
如果打算下雪,你可以跳过逆转
a.map(&:values).to_h.values_at(*b.values).compact.uniq
#=> ["wind", "snow", "fire"]
无论哪种方式,这都是一个奇怪的数据结构,这些答案只是为了帮助解决所提供的问题,因为重复的颜色会根据a
中的顺序导致不同的结果。
我相信你希望'snow'出现在你的输出数组中,因为没有其他合乎逻辑的解释。如果您要在第2行的末尾添加.to_h
,您的代码将会起作用,但正如您所说,它不是非常干净或高效。此外,通过转换为哈希,由于重复键,您可能会丢失数据。
这是一个更紧凑的结构,可以避免数据丢失问题:
def unique_elements(a, b)
color_set = b.values.to_set
a.map { |pair| pair[:name] if color_set.include?(pair[:color]) }.compact.uniq
end
首先,我们获取b
的值并将它们转换为集合,以便我们可以有效地确定给定元素是否是集合的成员。
接下来,我们映射a
,选择a
成员的名字,其中[:color]
包含在我们的颜色集中。
最后,我们消除nils
(使用compact
)并选择唯一值。
>> unique_elements(a, b)
#> ["wind", "fire", "snow"]
我首先将a
转换为更有用的数据结构。
h = a.each_with_object({}) { |g,h| h[g[:color]] = g[:name] }
#=> {"blue"=>"wind", "red"=>"fire", "white"=>"wind", "yellow"=>"wind",
# "green"=>nil, "black"=>"snow"}
然后我们可以简单地写
h.values_at(*b.values).compact.uniq
# => ["wind", "fire", "snow"]
这种方法有几个可取的特征:
h
的创建使该方法更容易阅读h
创建为单独的步骤,可以更轻松地进行调试和测试h
值,也只需要创建一次b
(在这种情况下,我们可能希望使h
成为一个实例变量)。h
可以链接到第二个声明,但我选择不这样做是出于上面给出的原因(特别是最后一个)。