查询 CSV::Table 以在普通的旧 ruby 脚本中查找两个给定日期之间销售额最多的项目
Posted
技术标签:
【中文标题】查询 CSV::Table 以在普通的旧 ruby 脚本中查找两个给定日期之间销售额最多的项目【英文标题】:querying a CSV::Table to find item with most sales between two given dates in plain old ruby script 【发布时间】:2020-04-06 09:15:43 【问题描述】:我试图找出两个给定日期之间的最高销售额。
这是我的带有标题的 ad_report.csv 文件:
date,impressions,clicks,sales,ad_spend,keyword_id,asin
2017-06-19,4451,1006,608,24.87,UVOLBWHILJ,63N02JK10S
2017-06-18,5283,3237,1233,85.06,UVOLBWHILJ,63N02JK10S
2017-06-17,0,0,0,21.77,UVOLBWHILJ,63N02JK10S
...
以下是我拥有的所有工作代码,它们返回具有最高值的行,但不在给定日期之间。
require 'csv'
require 'date'
# get directory of the current file
LIB_DIR = File.dirname(__FILE__)
# get the absolute path of the ad_report & product_report CSV
# and set to a var
AD_CSV_PATH = File.expand_path('data/ad_report.csv', LIB_DIR)
PROD_CSV_PATH = File.expand_path('data/product_report.csv', LIB_DIR)
# create CSV::Table for ad-ad_report and product_report CSV
ad_report_table = CSV.parse(File.read(AD_CSV_PATH), headers: true)
prod_report_table = CSV.parse(File.read(PROD_CSV_PATH), headers: true)
## finds the row with the highest sales
sales_row = ad_report_table.max_by |row| row[3].to_i
At this point I can get the row that has the greatest sale, and all the data from that row, but it is not in the excepted range.
Below I am trying to use range with the preset dates.
## range of date for items between
first_date = Date.new(2017, 05, 02)
last_date = Date.new(2017, 05, 31)
range = (first_date...last_date)
puts sales_row
下面是我觉得我应该做的 sudo 代码,但可能有更好的方法。
## check for highest sales
## return sales if between date
## else reject col if
## loop this until it returns date between
## return result
【问题讨论】:
CSV 不能替代数据库。相反,它是一种用于在电子表格或数据库之间传输数据的文件格式。搜索或读取 CSV 文件以生成报告是确定任何类型信息的缓慢方法。最终,一旦 CSV 读数太大而无法放入内存中,它就会导致问题。我建议研究 DBM,因为即使 SQLite 也会使这项任务变得更快、更容易。使用 ORM 也会使您的代码更加灵活;我推荐 Sequel 但 YMMV。 欢迎来到 SO!我看不到您在哪里尝试与您的日期范围进行比较。请尝试写下,然后如果您有问题,请提出问题。因为你的问题还为时过早。 “Stack Overflow question checklist”和“MCVE”帮助解释这个过程。 @theTinMan,总的来说,我不能不同意,但在某些情况下,CSV 文件是给定的,由其他人制作,并且只能读取一次,在这种情况下它可能不会感觉将其读入数据库,然后提取感兴趣的信息。此外,在这种情况下,无需将 CSV 文件吞入内存;可以逐行阅读。 @CarySwoveland 可能在报告或总结的情况下,文件可以立即丢弃并传递摘要,但这是我多年来从未遇到过的情况。将生成摘要而不是在 CVS 数据库转储中传递。如果数据来自组织/公司内部,则可以从 DBM 内部访问数据。数据库要快得多,并且可以在很短的时间内完成相同的查找。这听起来确实像是一个 XY 问题的案例......“What is the XY problem?”。 【参考方案1】:您可以按如下方式获得所需的值。我假设感兴趣的字段 ('sales'
) 表示整数值。如果不是,请将下面的.to_i
更改为.to_f
。
代码
require 'csv'
def greatest(fname, max_field, date_field, date_range)
largest = nil
CSV.foreach(fname, headers:true) do |csv|
largest = row: csv.to_a, value: csv[max_field].to_i if
date_range.cover?(csv[date_field]) &&
(largest.nil? || csv[max_field].to_i > largest[:value])
end
largest.nil? ? nil : largest[:row].to_h
end
示例
让我们首先创建一个 CSV 文件。
str =<<~END
date,impressions,clicks,sales,ad_spend,keyword_id,asin
2017-06-19,4451,1006,608,24.87,UVOLBWHILJ,63N02JK10S
2017-06-18,5283,3237,1233,85.06,UVOLBWHILJ,63N02JK10S
2017-06-17,0,0,0,21.77,UVOLBWHILJ,63N02JK10S
2017-06-20,4451,1006,200000,24.87,UVOLBWHILJ,63N02JK10S
END
fname = 't.csv'
File.write(fname, str)
#=> 263
现在找出给定日期范围内“销售额”值最大的记录。
greatest(fname, 'sales', 'date', '2017-06-17'..'2017-06-19')
#=> "date"=>"2017-06-18", "impressions"=>"5283", "clicks"=>"3237",
# "sales"=>"1233", "ad_spend"=>"85.06", "keyword_id"=>"UVOLBWHILJ",
# "asin"=>"63N02JK10S"
greatest(fname, 'sales', 'date', '2017-06-17'..'2017-06-25')
#=> "date"=>"2017-06-20", "impressions"=>"4451", "clicks"=>"1006",
# "sales"=>"200000", "ad_spend"=>"24.87", "keyword_id"=>"UVOLBWHILJ",
# "asin"=>"63N02JK10S"
greatest(fname, 'sales', 'date', '2017-06-22'..'2017-06-25')
#=> nil
我逐行读取文件(使用CSV#foreach)以将内存要求降至最低,如果文件很大,这可能是必不可少的。
请注意,由于日期为“yyyy-mm-dd”格式,因此无需将两个日期转换为Date
对象进行比较;也就是说,它们可以作为字符串进行比较(例如'2017-06-17' <= '2017-06-18' #=> true
)。
【讨论】:
【参考方案2】:您可以通过创建一个包含两个日期的范围来做到这一点,然后使用Range#cover?
来测试日期是否在该范围内:
range = Date.new(2015-01-01)..Date.new(2020-01-01)
rows.select do |row|
range.cover?(Date.parse(row[1]))
end.max_by |row| row[3].to_i
虽然铁皮人是完全正确的,你应该使用数据库来代替。
【讨论】:
进展很慢。好的。我想完成这个解决方案,然后我会尝试使用数据库。谢谢! 您期待什么?您正在解析人类已知的最糟糕的格式并循环遍历 Ruby 中的一个巨大对象。当然它很慢。以上是关于查询 CSV::Table 以在普通的旧 ruby 脚本中查找两个给定日期之间销售额最多的项目的主要内容,如果未能解决你的问题,请参考以下文章
Google Big Query Error: CSV table 遇到太多错误,放弃。行:1 错误:1
使用标准库Ruby将数据标记到Elasticsearch批量中