我如何在Ruby中分配多个符号到相同的值?



我想做的是将同义词符号聚集到相同的值,而不必一遍又一遍地重新定义相同的值。基本上就是把这个转过来:

fruits = { orange: "Citrus", grapefruit: "Citrus", tangerine: "Citrus" }

这:

fruits = { orange:, grapefruit:, tangerine: => "Citrus" }

完成此操作的正确语法是什么?

感谢

使用散列,以便使用水果名称访问水果的类型。例如:

fruits = %i{ orange grapefruit tangerine apple }
citrus_fruits = %i{ orange grapefruit tangerine }
fruit_type = citrus_fruits.zip([:citrus] * citrus_fruits.length).to_h
fruit_type[:apple] = :rosaceae
puts fruit_type
# {:orange=>:citrus, :grapefruit=>:citrus, :tangerine=>:citrus, :apple=>:rosaceae}

这里,zipto_h用于简化哈希创建,避免重复代码。

按值分组键;可选转换返回值

在Ruby中,Symbol是一个核心类,它为事物提供标识符,并且Symbol在运行时不会被复制。抛开它们在内部的使用方式不谈,在代码中使用Symbol的最常见用例是在散列中定义键。你也可以使用其他类型的键,但是Symbol的属性使得它们作为Hash键特别有用。

解决了这个问题后,看起来您正在尝试对类似的哈希值进行分组,但是不清楚您希望如何使用这个分组。有不止一种方法可以做到这一点,所以我只选一种作为例子。

给定一个像这样的Hash:

produce =
{
:orange => "citrus",
:grapefruit => "citrus",
:tangerine => "citrus",
:raspberry => "berry",
:strawberry => "berry",
:canteloupe => "melon",
:honeydew => "melon"
}

你可以使用hash# group_by(继承自Enumerable)来快速排序你的Hash值。例如,使用Ruby 3.0.0:

produce.group_by { _2 }
#=> 
{"citrus"=>
[[:orange, "citrus"], [:grapefruit, "citrus"], [:tangerine, "citrus"]],
"berry"=>[[:raspberry, "berry"], [:strawberry, "berry"]],
"melon"=>[[:canteloupe, "melon"], [:honeydew, "melon"]]}

返回一个按您的唯一值分组的散列,但是您可能更愿意放弃嵌套数组对象中的produce类型。你可以这样做hash# transform_values:

produce.group_by { _2 }.transform_values { _1.map &:first }
#=> 
{"citrus"=>[:orange, :grapefruit, :tangerine],
"berry"=>[:raspberry, :strawberry],
"melon"=>[:canteloupe, :honeydew]}

无论哪种方式,重点是哈希键与几乎可以是任何类的值相关联,因此您可以检查每个值的内容以确定它们是否属于您想要的分组(当前由您的键定义)。

您当前的数据结构并没有真正优化检索类型的产品(例如柑橘类水果),但它肯定可以做到。但是,您可能需要重新考虑是否拥有适合访问或操作数据的正确数据结构。你的里程肯定会有所不同。

你对主板和蓝图的评论表明你得到了类似

的东西
h = { :mb1=>:bp3, :mb_2=>:bp1, :mb3=>:bp3, :mb4=>:bp2, :mb5=>:bp1 }

,并希望生成哈希值

{ :bp3=>[:mb1, :mb3], :bp1=>[:mb_2, :mb5], :bp2=>[:mb4] }

这样做的方法之一是:

h.each_with_object({}) { |(k,v),g| (g[v] ||= []) << k }

请参阅Enumerable#each_with_object,并了解为什么我编写了块变量|(k,v),g|,请参阅数组分解。

这是以下代码的浓缩翻译(我用三个puts语句来显示正在执行的计算):

g = {}
h.each do |key_value_pair|
k, v =  key_value_pair
puts "nkey_value_pair = #{key_value_pair}, k = #{k}, v = #{v}"
puts "g[#{v}] set to [] because g[#{v}] == nil" if g[v].nil?   
g[v] = [] if g[v].nil?
g[v] << k
puts "g after g[#{v}] << #{g}"   
end
#=> {:mb1=>:bp3, :mb_2=>:bp1, :mb3=>:bp3, :mb4=>:bp2, :mb5=>:bp1}

显示如下:

key_value_pair = [:mb1, :bp3], k = mb1, v = bp3
g[bp3] set to [] because g[bp3] == nil
g after g[bp3] << {:bp3=>[:mb1]}
key_value_pair = [:mb_2, :bp1], k = mb_2, v = bp1
g[bp1] set to [] because g[bp1] == nil
g after g[bp1] << {:bp3=>[:mb1], :bp1=>[:mb_2]}
key_value_pair = [:mb3, :bp3], k = mb3, v = bp3
g after g[bp3] << {:bp3=>[:mb1, :mb3], :bp1=>[:mb_2]}
key_value_pair = [:mb4, :bp2], k = mb4, v = bp2
g[bp2] set to [] because g[bp2] == nil
g after g[bp2] << {:bp3=>[:mb1, :mb3], :bp1=>[:mb_2], :bp2=>[:mb4]}
key_value_pair = [:mb5, :bp1], k = mb5, v = bp1
g after g[bp1] << {:bp3=>[:mb1, :mb3], :bp1=>[:mb_2, :mb5], :bp2=>[:mb4]}

@Charles Persson,如果我对你的问题理解正确的话,你的主要目标是重构这个代码片段:

hash = {
:orange     => "citrus",
:grapefruit => "citrus",
:tangerine  => "citrus",
:raspberry  => "berry",
:cherry     => "drupe",
:strawberry => "berry",
:canteloupe => "melon",
:honeydew   => "melon",
:apple      => "pome"
}

变成类似于:

hash = {
[:orange, :grapefruit, :tangerine] => "citrus",
[:raspberry, :strawberry]          => "berry",
:cherry                            => "drupe",
[:canteloupe, :honeydew]           => "melon",
:apple                             => "pome"
}

如果我是对的,那么我可以建议实现这样一个方法:

# source - an input hash that can contain arrays as keys.
# dest - a new output hash where all array keys are replaced by singular keys.
def mhash(source)
dest = {}
source.each_pair do |key, value|
if key.instance_of?(Array)
key.each do |sub_key|
dest[sub_key] = value
end
else
dest[key] = value
end
end
dest
end

或其更短的替代:

def mhash(source)
source.each_pair.with_object({}) do |(key, value), dest|
key.instance_of?(Array) ? key.each { |sub_key| dest[sub_key] = value } : dest[key] = value
end
end

这样,您将能够编写如下代码:

hash = mhash({
[:orange, :grapefruit, :tangerine] => "citrus",
[:raspberry, :strawberry]          => "berry",
:cherry                            => "drupe",
[:canteloupe, :honeydew]           => "melon",
:apple                             => "pome"
})
p hash
# => {
:orange     => "citrus",
:grapefruit => "citrus",
:tangerine  => "citrus",
:raspberry  => "berry",
:strawberry => "berry",
:cherry     => "drupe",
:canteloupe => "melon",
:honeydew   => "melon",
:apple      => "pome"
}

否则,请提供一个更好的解释你的问题。谢谢。

最新更新