【问题标题】:merge CSV files on a common field with ruby/fastercsv使用 ruby​​/fastercsv 合并公共字段上的 CSV 文件
【发布时间】:2011-12-18 07:41:48
【问题描述】:

我有一个包含许多列的“主”文件:1 2 3 4 5。我还有一些其他文件,其行数少于主文件,每个文件的列数:1 6。我想合并这些文件在第 1 列字段上匹配,并将第 6 列添加到主文件。我见过一些 python/UNIX 解决方案,但如果它适合的话,我更喜欢使用 ruby​​/fastercsv。如有任何帮助,我将不胜感激。

【问题讨论】:

  • 文件是否按第 1 列排序?它们很大吗?你能把其他文件放在内存中吗?
  • 文件可以按第一列排序,但我与主文件匹配的文件有一部分行。文件可以全部放入内存,主文件最大为 2000 行 20 列。较小的文件小于 270 行。谢谢你的问题...

标签: ruby fastercsv


【解决方案1】:
$ cat j4.csv
how, now, brown, cow, f1
now, is, the, time, f2
one, two, three, four, five
xhow, now, brown, cow, f1
xnow, is, the, time, f2
xone, two, three, four, five
$ cat j4a.csv
how, b
one, d
$ cat hj.rb
require 'pp'
require 'rubygems'
require 'fastercsv'

pp(
  FasterCSV.read('j4a.csv').inject(
    FasterCSV.read('j4.csv').inject({}) do |m, e|
      m[e[0]] = e
      m
    end) do |m, e|
    k = e[0]
    m[k] << e.last if m[k]
    m
  end.values)
$ ruby hj.rb
[["now", " is", " the", " time", " f2"],
 ["xhow", " now", " brown", " cow", " f1"],
 ["xone", " two", " three", " four", " five"],
 ["how", " now", " brown", " cow", " f1", " b"],
 ["one", " two", " three", " four", " five", " d"],
 ["xnow", " is", " the", " time", " f2"]]

这通过将您的主文件映射到以第一列作为键的哈希值来工作,然后它只是从您的其他文件中查找键。正如所写的那样,当键匹配时,代码会附加最后一列。由于您有多个非主文件,您可以通过将 FasterCSV.read('j4a.csv') 替换为读取每个文件并将它们全部连接到单个数组数组中的方法来调整概念,或者您可以只保存内部 @ 的结果987654323@(主哈希)并循环应用其他文件。

【讨论】:

  • 感谢 DigitalRoss,这是非常有用的代码,我花了一些时间来浏览并查看发生了什么...
【解决方案2】:

FasterCSV 现在是 Ruby 1.9 中的默认 CSV 实现。此代码未经测试,但应该可以工作。

require 'csv'
master = CSV.read('master.csv') # Reads in master
master.each {|each| each.push('')} # Adds another column to all rows
Dir.glob('*.csv').each do |each| #Goes thru all csv files
  next if each == 'master.csv' # skips the master csv file
  file = CSV.read(each) # Reads in each one
  file.each do |line| #Goes thru each line of the file
    temp = master.assoc(line[0]) # Finds the appropriate line in master
    temp[-1] = line[1] if temp #updates last column if line is found
  end
end

csv = CSV.open('output.csv','wb') #opens output csv file for writing
master.each {|each| csv << each} #Goes thru modified master and saves it to file

【讨论】:

  • 谢谢卡西姆。我正在尝试解决错误(ruby 1.8.7):combine.rb:8: syntax error, unexpected kIN in = master.assoc(line[0]) # Finds the appropriate line in master
  • 如果您使用的是 ruby​​ 1.8.7,请确保将 CSV 更改为 FasterCSV。我也更新了我的帖子,犯了一个愚蠢的错误......
  • 这里没有指指点点。仍然出现错误:combine.rb:15: undefined local variable or method `csv' for main:Object (NameError)。这里没有足够的空间来显示所有代码,但我将 CSV 的所有实例都更改为 FasterCSV,但 CSV.open 除外 - 使 FCSV.open 成为可能,对吗?也改变了需要'fastercsv'。再次感谢,希望这不是信天翁代码...
  • 很抱歉。照原样,此代码在 1.8.7 和 1.9.3 上运行没有任何问题,我现在已经对其进行了全面测试。
  • Kassym,问题在我这边。得到CSV::IllegalFormatError,原来是我的Mac CR,改成LF,一切都很好。非常感谢您的时间和帮助。
【解决方案3】:
temp = master.assoc(line[0]) 

以上是一个超级慢的过程。整个复数至少为 O(n^2)。

我会使用以下流程:

  1. 对于 1 6 csv,将其转换为以 1 为键、6 为值的大哈希, 命名为 1_to_6_hash
  2. 逐行循环1 2 3 4 5 csv,设置row[6] = 1_to_6_hash[row[1]]

它会大大降低复杂度到 O(n)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-19
    • 2016-01-16
    • 1970-01-01
    • 2015-12-22
    • 2022-11-22
    • 1970-01-01
    • 1970-01-01
    • 2021-03-08
    相关资源
    最近更新 更多