根据输入哈希从哈希数组中查找uniq值

时间:2018-03-15 12:07:10

标签: ruby

我有一个数组和一个哈希:

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

我需要一个更好的方法。这个有太多的循环。

3 个答案:

答案 0 :(得分:2)

虽然你的结果对我来说没有意义(例如它缺少雪)但这将起作用

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中的顺序的不同结果。

答案 1 :(得分:1)

我相信你想要&#39; snow&#39;在你的输出数组中,因为没有其他逻辑解释。如果您要在第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"]

答案 2 :(得分:1)

我首先将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可以链接到第二个声明,但由于上面给出的原因(特别是最后一个),我选择不这样做。