我正在打开一个包含与代码相关的条款的文件。文件中的一行显示如下:
Pacific Ocean; D01.330.322
我希望它们出现在哈希中。有些术语出现不止一次,我希望将其值放在由","
连接的一个字符串中。我的代码是:
descriptor_code_hash = Hash.new
File.open('mtrees2014.bin').each do |file_line|
file_line = file_line.chomp
mesh_descriptor, tree_code = file_line.split(/\;/)
descriptor_code_hash[mesh_descriptor] = tree_code
if descriptor_code_hash.has_key? mesh_descriptor
tree_code << "," << tree_code
else
descriptor_code_hash[mesh_descriptor]
end
end
当一个术语有多个代码时,相同的代码会连接一次,并且不会识别该术语的其他唯一代码。此外,我不知道如何编写脚本来获取所有代码,例如,一些术语有六个代码。
答案 0 :(得分:1)
你的代码并不遥远。我们来看看吧。
测试数据
以下是一些用于测试的数据:
oceans = ["Pacific; 1", "Atlantic; 2", "Indian; 3",
"Pacific; 2", "Atlantic; 1", "Pacific; 3"]
我没有读取文件的行,而是通过从字符串数组中读取来简化操作。一旦代码工作,它就足够简单,可以将其更改为从文件中读取。
现在我们有了一些输入数据,我们可以显示我们想要的预期结果,
hash =
{ 'Pacific' => ['1', '2', '3'],
'Atlantic' => ['2', '1'],
'Indian' => ['1'] }
或
hash =
{ 'Pacific' => "'1', '2', '3'",
'Atlantic' => "'2', '1'",
'Indian' => "'1'" }
我们将使用第一个,因为它最容易处理,如果我们想要第二个表单,我们可以从第一个表单轻松计算它:
hash.keys.each { |k| hash[k] = hash[k].join(',') }
#=> ["Pacific", "Atlantic", "Indian"]
但是,等等,这不是返回的哈希值。不,这是hash.keys
。我们想要的是hash
的新值:
hash #=> {"Pacific"=>"1,2,3", "Atlantic"=>"2,1", "Indian"=>"1"}
除此之外:在向SO发布问题时,将一些说明性输入数据与预期结果一起包含通常很有帮助。这往往澄清,并保存文字。尝试使用尽可能少的数据。
您的代码
这是你的代码,数组oceans
代替了文件的读取:
descriptor_code_hash = Hash.new
oceans.each do |file_line|
file_line = file_line.chomp
mesh_descriptor, tree_code = file_line.split(/\;/)
descriptor_code_hash[mesh_descriptor] = tree_code
if descriptor_code_hash.has_key? mesh_descriptor
tree_code << "," << tree_code
else
descriptor_code_hash[mesh_descriptor]
end
end
主要问题是:
descriptor_code_hash[mesh_descriptor] = tree_code
每次循环时,键descriptor_code_hash
的{{1}}值会重置为mesh_descriptor
的当前元素tree_code
的值(表示一行的文件)。你需要删除这一行。
接下来,我们需要更改您的oceans
语句,如下所示:
if/else/end
这为您提供以下内容:
if descriptor_code_hash.has_key? mesh_descriptor
descriptor_code_hash[mesh_descriptor] << tree_code
else
descriptor_code_hash[mesh_descriptor] = [tree_code]
end
当我们运行时,我们获得:
descriptor_code_hash = Hash.new
oceans.each do |file_line|
file_line = file_line.chomp
mesh_descriptor, tree_code = file_line.split(/\;/)
if descriptor_code_hash.has_key? mesh_descriptor
descriptor_code_hash[mesh_descriptor] << tree_code
else
descriptor_code_hash[mesh_descriptor] = [tree_code]
end
end
如您所见,结果是正确的,除了存在轻微的格式问题。我们可以通过改变来解决这个问题:
descriptor_code_hash
#=> {"Pacific"=>[" 1", " 2", " 3"], "Atlantic"=>[" 2", " 1"],
# "Indian"=>[" 3"]}
到
file_line.split(/\;/)
可以通过两种方式简化:
file_line.split(/\;/).map { |w| w.strip }
我们来试试吧。假设:
file_line.split(';').map(&:strip)
然后
file_line = "Pacific; 1\n"
这是期望的结果。请注意,我在字符串的末尾添加了换行符。那是为了告诉你file_line.split(';').map(&:strip) #=> ["Pacific", "1"]
删除它以及空格。这意味着您不需要上一行:
strip
(file_line = file_line.chomp
也有效。)
您的代码现在简化为:
file_line.chomp.split(/\s*;\s*/)
<强>抛光强>
现在考虑一下你可以做些什么来使你的代码更像Ruby。首先,查看@BroiSatse给出的答案中使用的以下行(代替您的descriptor_code_hash = Hash.new
oceans.each do |file_line|
mesh_descriptor, tree_code = file_line.split(';').map(&:strip)
if descriptor_code_hash.has_key? mesh_descriptor
descriptor_code_hash[mesh_descriptor] << tree_code
else
descriptor_code_hash[mesh_descriptor] = [tree_code]
end
end
构造):
if/else/end
对于任何变量(descriptor_code_hash[mesh_descriptor] ||= []) << tree_code
,a
与a ||= []
相同。如果尚未定义a = (a || [])
,则它将等于a
,因此nil
。如果已为(nil || []) => []
分配了(非零)值a
。换句话说,如果(a || []) => a
没有键descriptor_code_hash
(意为mesh_descriptor
),descriptor_code_hash[mesh_descriptor] => nil
将被分配descriptor_code_hash[mesh_descriptor]
;否则,它将被自己分配(即,它不会改变)。
在
[]
执行,descriptor_code_hash[mesh_descriptor] ||= []
将等于数组,空或其他。 descriptor_code_hash[mesh_descriptor]
然后将<< tree_code
附加到哈希值(数组)。最后,我们可以使用tree_code
而不是{}
,但这纯粹是一种风格选择。
您的代码现在看起来像这样:
Hash.new
现在让我们将其作为一种方法并进行一些更改:
descriptor_code_hash = {}
oceans.each do |file_line|
mesh_descriptor, tree_code = file_line.split(';').map(&:strip)
(descriptor_code_hash[mesh_descriptor] ||= []) << tree_code
end
我简化了一些变量名称,因为该方法的目的是通过其名称来描述的。仔细阅读Enumerable#each_with_object的文档(自1.9版开始提供)以了解它的使用方法。
您可能希望将文件名作为方法参数。
最后一件事:你可以改写如下:
def descriptor_code_hash(oceans)
oceans.each_with_object({}) do |line, hash|
mesh_descriptor, tree_code = line.split(';').map(&:strip)
(hash[mesh_descriptor] ||= []) << tree_code
end
end
descriptor_code_hash(oceans)
#=> {"Pacific"=>["1", "2", "3"], "Atlantic"=>["2", "1"], "Indian"=>["3"]}
此处对象初始化为:
def descriptor_code_hash(oceans)
oceans.each_with_object(Hash.new {|k,h| h[k] = {} }) do |line, hash|
mesh_descriptor, tree_code = line.split(';').map(&:strip)
hash[mesh_descriptor] << tree_code
end
end
使得默认值(对于将新键添加到哈希时)为空哈希。这就是为什么第三到最后一行可以简化如图所示。
答案 1 :(得分:0)
尝试:
descriptor_code_hash = Hash.new
File.open('mtrees2014.bin').each do |file_line|
file_line = file_line.chomp
mesh_descriptor, tree_code = file_line.split(/\;/)
(descriptor_code_hash[mesh_descriptor] ||= []) << tree_code
end
这种方式descriptor_code_has[key]
是一个数组,其中包含来自文件的给定键的所有代码。