Ruby on rails 我如何加快Ruby/Rake任务的速度,该任务统计30万个日期字符串中出现的日期?
我有一个300K字符串数组,表示日期:Ruby on rails 我如何加快Ruby/Rake任务的速度,该任务统计30万个日期字符串中出现的日期?,ruby-on-rails,ruby,performance,optimization,rake,Ruby On Rails,Ruby,Performance,Optimization,Rake,我有一个300K字符串数组,表示日期: date_array = [ "2007-03-25 14:24:29", "2007-03-25 14:27:00", ... ] 我需要计算此数组中每个日期的出现次数(例如,“2011-03-25”的所有日期字符串)。确切的时间并不重要,只是日期。我知道文件中的日期范围。因此,我: Date.parse('2007-03-23').upto Date.parse('2011-10-06') do |date_to_count| cou
date_array = [
"2007-03-25 14:24:29",
"2007-03-25 14:27:00",
...
]
我需要计算此数组中每个日期的出现次数(例如,“2011-03-25”的所有日期字符串)。确切的时间并不重要,只是日期。我知道文件中的日期范围。因此,我:
Date.parse('2007-03-23').upto Date.parse('2011-10-06') do |date_to_count|
count = 0
date_array.each do |date_string|
if Date.parse(date_string) >= date_to_count &&
Date.parse(date_string) <= date_to_count
count += 1
end
end
puts "#{date_to_count} occurred #{count} times."
end
Date.parse('2007-03-23')。update.parse('2011-10-06')do | Date|to|u count|
计数=0
日期数组。每个do |日期字符串|
如果Date.parse(Date\u string)>=Date\u to\u count&&
parse(Date\u string)这是一个非常糟糕的算法。您正在扫描每个日期的整个列表,而且,您在没有明显原因的情况下两次解析同一日期。这意味着对范围内的N个日期和列表中的M个日期进行N*M*2次日期解析
您真正需要的是使用group\u by
并一次性完成:
dates = date_array.group_by do |date_string|
Date.parse(date_string)
end
然后您可以将其用作计数的参考:
Date.parse('2007-03-23').upto Date.parse('2011-10-06') do |date_to_count|
puts "#{date_to_count} occurred #{dates[date_to_count] ? dates[date_to_count].length : 0} times."
end
是的,如果日期的格式相同,则根本不需要解析日期。了解您的数据是您可以拥有的最强大的工具之一
如果datetime字符串的格式都相同(yyyy-mm-dd HH:mm:SS),则可以执行以下操作
data_array.group_by{|datetime| datetime[0..9]}
这将为您提供一个类似的哈希,其中日期字符串作为键,日期数组作为值
{
"2007-05-06" => [...],
"2007-05-07" => [...],
...
}
{
"2007-05-06" => 123,
"2007-05-07" => 456,
...
}
所以你必须得到每个数组的长度
data_array.group_by{|datetime| datatime[0..9]}.each do |date_string, date_array|
puts "#{date_string} occurred #{date_array.length} times."
end
当然,当您不需要日期数组时,这种方法是在浪费内存
那你呢
一种更节省内存的方法
date_counts = {}
date_array.each do |date_string|
date = date_string[0..9]
date_counts[date] ||= 0 # initialize count if necessary
date_counts[date] += 1
end
您将得到一个哈希,日期字符串作为键,计数作为值
{
"2007-05-06" => [...],
"2007-05-07" => [...],
...
}
{
"2007-05-06" => 123,
"2007-05-07" => 456,
...
}
将所有内容组合在一起
date_counts = {}
date_array.each do |date_string|
date = date_string[0..9]
date_counts[date] ||= 0 # initialize count if necessary
date_counts[date] += 1
end
Date.parse('2007-03-23').upto Date.parse('2011-10-06') do |date_to_count|
puts "#{date_to_count} occurred #{date_counts[date_to_count.to_s].to_i} times."
end
我同意。在我的笔记本电脑上解析30万个日期需要45秒。像这样切片需要0.12秒。哇。非常感谢你。0.48秒。这些计数器哈希的另一个技巧是:date_counts=Hash.new{h,k{h[k]=0}
,它总是自动将任何键预初始化为零。如果你有创意的话,Hash.new
的块可以做各种神奇的事情。这将确保始终定义请求的任何密钥,因此无需检查nil
。感谢您的回答。它教会了我一些有用的东西。我同意向导的答案,因为在我的具体情况下,避免解析日期首先会使通用解决方案更快。完全不解析肯定是更好的解决方案。