我正在进行迭代:this的时间定位部分(来自Jumpstart Lab的活动管理器练习)。我想出了如何迭代数组并将其转换为this线程的哈希值。这就是我所拥有的:
require "date"
time = ["11/12/08 10:47","11/12/08 13:23","11/12/08 13:30","11/12/08 14:04","11/12/08 14:46"]
#makes array of all times
time.each do |time|
@array = Array(DateTime.strptime(time,'%m/%d/%Y %H:%M').hour)
end
#makes hash of :time => number of instances
result = Hash.new(0)
@array.each do |time|
result[time] += 1
end
puts result
我运行时得到的哈希是{ 14 => 1 }
,这不是我想要的。我怀疑这是因为我的数组是由整数组成的,而不是像示例那样的字符串。有没有办法在整数上实现相同的效果?或者我必须将整数转换为字符串?如果我必须转换为字符串,我应该在哪里放置to_s
?
答案 0 :(得分:2)
这个逻辑错误:
time.each do |time|
@array = Array(DateTime.strptime(time,'%m/%d/%Y %H:%M').hour)
end
循环的主体每次替换 @array
的内容,所以你只有在完成后才能获得最后一个元素。此外,使用time
作为内部变量名称会令人困惑(并且在旧版本的Ruby中具有破坏性)。
你想要的是追加到循环中<<
的数组,而不是使用=
分配:
@array = []
time.each do |t|
@array << DateTime.strptime(t, '%m/%d/%Y %H:%M').hour
end
但这是构建数组的一种非常程序化的方式,而不是非常Rubyish。惯用的方法是使用map
一次构造新数组:
@array = time.map { |t| DateTime.strptime(t, '%m/%d/%Y %H:%M').hour }
作为旁注,我不确定你为什么决定让@array
成为实例变量。你可以称之为array
;对数组使用@
是一个Perl的东西,而不是Ruby。
无论如何,一旦你修复了@array
的创建,你构建计数哈希的逻辑应该按原样运行。但是,您可以使用reduce
以类似的方式构建它;这只是一种可能性:
result = @array.reduce({}) { |h, t| h.merge({t => h[t]+1}) }
您可以使用名为group_by
的Ruby数组的内置方法进一步简化逻辑。这个电话:
time.group_by { |t| DateTime.strptime(t, '%m/%d/%Y %H:%M').hour }
返回此哈希:
{10=>["11/12/08 10:47"], 13=>["11/12/08 13:23", "11/12/08 13:30"], 14=>["11/12/08 14:04", "11/12/08 14:46"]}
这与result
中的内容很接近;您所要做的就是用长度替换这些数组值。幸运的是,map
也适用于Hashes,但它返回的是一个数组而不是另一个Hash,所以你必须在完成后将其转换回来。这样就可以了:
result = Hash[time.group_by { |t| DateTime.strptime(t, '%m/%d/%Y %H:%M').hour }.map{|k,v| [k, v.length]}]
答案 1 :(得分:1)
你可以用一行得到结果:
result = Hash[time.group_by{|str| DateTime.strptime(str,'%m/%d/%Y %H:%M').hour}.map{|k,v| [k, v.count]}]
的说明:强> 的
实际上,有三个步骤:
> step_1 = time.group_by{|str| DateTime.strptime(str,'%m/%d/%Y %H:%M').hour}
=> {10=>["11/12/08 10:47"], 13=>["11/12/08 13:23", "11/12/08 13:30"], 14=>["11/12/08 14:04", "11/12/08 14:46"]}
> step_2 = step_1.map{|k,v| [k, v.count]}
=> [[10, 1], [13, 2], [14, 2]]
> step_3 = Hash[step_2]
=> {10=>1, 13=>2, 14=>2}
答案 2 :(得分:1)
为作业选择正确的数据结构非常重要。在这种情况下,正确的数据结构不是Hash
,而是Multiset
。 [不幸的是,标准库或核心库中没有Multiset
,但有一个multiset
gem。]
require 'date'
require 'multiset'
time = [
'11/12/08 10:47',
'11/12/08 13:23',
'11/12/08 13:30',
'11/12/08 14:04',
'11/12/08 14:46'
]
Multiset[*time.map {|t| DateTime.strptime(t, '%m/%d/%Y %H:%M').hour }]
# => #<Multiset:#1 10, #2 13, #2 14>
如您所见,第十个小时有一个条目,第13个小时和第14个小时分别有两个条目。