我有下面这个复杂的哈希结构(在许多哈希结构中),看起来如下:
hash = {"en-us"=>
{:learn_more=>"Learn more",
:non_apple_desktop=>"To redeem, open this link.",
:value_prop_safety=>"",
:storage_size=>
{:apple_tv_1_month_tms=>
{:cta=>"Offer",
:details=>"Get a 1-month subscription!.",
:disclaimer=>"This offer expires on December 10, 2021.",
:header=>"Watch The Morning Show ",
:normal_price=>"$2.99"}
}
}
}
我想做的是创建一个函数,它将基于哈希结构生成以下字符串输出:
en-us.storage_size.apple_tv_1_month_tms.cta: Offer
en-us.storage_size.apple_tv_1_month_tms.details: Get a 1-month subscription!.
en-us.storage_size.apple_tv_1_month_tms.disclaimer: This offer expires on December 10, 2021.
en-us.storage_size.apple_tv_1_month_tms.header: Watch The Morning Show
en-us.storage_size.apple_tv_1_month_tms.normal_price: $2.99
en-us.learn_more: Learn more
en-us.non_apple_desktop: To redeem, open this link.
en-us.value_prop_safety:
我使用了另一个stackoverflow问题中的递归函数,它在一定程度上完成了这一点:
def show(hash, current_path = '')
string = ''
hash.each do |k,v|
if v.respond_to?(:each)
current_path += "#{k}."
show v, current_path
else
string += "#{current_path}#{k}: #{v}" + "\n"
end
end
string
end
如果我把puts
语句放在方法体中,我可以看到想要的结果,但它是逐行的。我需要的是获得完整的输出,因为我将把它写入一个csv。我似乎不能让它在当前的化身中工作。
如果我把一个puts show(hash)
放到我的irb中,那么我将不会得到任何输出。
show(hash) ----->
en-us.storage_size.apple_tv_1_month_tms.cta: Offer
en-us.storage_size.apple_tv_1_month_tms.details: Get a 1-month subscription!.
en-us.storage_size.apple_tv_1_month_tms.disclaimer: This offer expires on December 10, 2021.
en-us.storage_size.apple_tv_1_month_tms.header: Watch The Morning Show
en-us.storage_size.apple_tv_1_month_tms.normal_price: $2.99
en-us.learn_more: Learn more
en-us.non_apple_desktop: To redeem, open this link.
en-us.value_prop_safety:
这应该是一个简单的递归任务,但我不能指出我到底错在哪里。帮助将是非常感激的。谢谢。
4条答案
按热度按时间n7taea2i1#
在我看来,使用
i18n
gem要方便得多它有一个
I18n::Backend::Flatten#flatten_translations
方法,它接收一个翻译的散列(其中键是一个locale,值是另一个散列),并返回一个所有翻译都扁平化的散列,这正是您所需要的只需将生成的哈希转换为字符串,就可以完成了
当然,最好不要包含在
main
对象中,而是包含在某个服务对象中elcex8rz2#
回答你的问题:
应该是
否则将丢失递归调用所做所有工作。
请注意,
a += b
会将a
替换为新字符串a + b
。它不会更改a
。因此,保留show
的返回值非常重要。如果你想依赖于字符串是可变的,这里有一个可变字符串版本;然而,注意它可能并不总是有效,因为字符串不变性是Ruby中增加的一个选项。如果
frozen_string_literals
是on,可变连接操作符<<
将失败。在可变字符串版本中,您不能在每次迭代中初始化string
,因为您将丢弃调用者已经完成的工作;因此它将作为另一个参数传递,并仅在初始调用时由默认值初始化。vnzz0bqm3#
方法的注意事项
一、几个问题:
en-us
不是有效的LANG值。您可以将其作为键使用,但如果区域设置很重要,您可能希望使用技术上更准确的值(如en_US
或en_US.UTF-8
)作为键。第二,如果您已经 * 知道 * JSON的结构,那么您只需将每个JSON键设置为一个列值并填充它,这可能要容易得多。
第三,虽然Ruby可以进行递归,但它的大多数内置方法都是为 iteration 设计的。迭代对于很多事情来说更快更容易,所以除非你有其他原因,否则只要迭代你需要的信息就行了。
从具有预定义格式的结构化数据构建CSV
最后,如果您只想将数据填充到CSV或创建字符串,那么您可能只想提取数据,然后将其与您已经知道的信息混合在一起。例如:
要获取顶级键的值,可以这样做:
如果做更多的工作,你可以使用ActiveSupport或者使用Ruby 3.1的模式匹配和查找模式来做类似的事情,但这也适用于较早的Ruby版本。唯一的缺点是它依赖于Hashie gem来进行Hashie::DeepFind,但这是Ruby没有一个简单的内置方法来查找嵌套结构的情况之一,而不是模式匹配,我认为这是值得的。
您仍然需要做一些工作来将提取的数据转换为您想要的格式,但这会将您想要的所有值转换为一对变量,offer_values 和 linking。然后您可以对它们做任何您想要的操作。
请参阅
除了Hashie::DeepFind和Ruby 3模式匹配之外,还有许多查询语言可能对从JSON中提取数据很有用,其中一些语言带有Ruby gem,或者可以很容易地集成到Ruby应用程序中:
vsdwdz234#
这是一个相对简单的递归,因为每个值都是一个字符串或哈希值。
第一个