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

问题描述 投票:-2回答:3

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

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

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

ruby
3个回答
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
投票

我相信你希望'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"]

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

© www.soinside.com 2019 - 2024. All rights reserved.