查询 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' &lt;= '2017-06-18' #=&gt; 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​​ 脚本中查找两个给定日期之间销售额最多的项目的主要内容,如果未能解决你的问题,请参考以下文章

ruby读取csv行数

Google Big Query Error: CSV table 遇到太多错误,放弃。行:1 错误:1

使用标准库Ruby将数据标记到Elasticsearch批量中

在方法中调用方法以在 Ruby 中进行 Titleize

如何编写 jmeter 测试以在网站内提交表单(Jmeter,ruby -jmeter)

如何设置正确的 Ruby 版本以在 Aptana 3 中与我的 Rails 5 项目一起使用?