【问题标题】:Extract duplicate records from CSV based on selected headings根据选定的标题从 CSV 中提取重复记录
【发布时间】:2011-08-23 11:28:51
【问题描述】:

我有一个包含数千个客户详细信息的 CSV 文件。我想根据所选标题的相同值来提取重复的客户。

例如,我想提取存在多个具有相同“姓氏”和“邮政编码”的记录的所有客户。

"surname","postcode","other-stuff-that-doesn't-matter"...
"smith",  "AB1 2CD", "dxfh"...
"smith",  "AB1 2CD", "98sf"...
"jones",  "BC2 3DE", "as0j"...
"jones",  "BC2 3DE", "9as6"...
"blogs",  "BC2 3DE", "9as6"...

基于上述,程序将返回一个新的 CSV,如下所示:

"surname","postcode","other-stuff-that-doesn't-matter"...
"smith",  "AB1 2CD", "dxfh"...
"smith",  "AB1 2CD", "98sf"...
"jones",  "BC2 3DE", "as0j"...
"jones",  "BC2 3DE", "9as6"...

编辑

感谢到目前为止的帮助。我想我有一个可行的解决方案,但我很想知道这是否可以优化(我相信它可以!)。

set_one    = Set.new
set_two    = Set.new
duplicates = Array.new
headers    = nil

CSV.foreach('customers.csv', :headers => true, :header_converters => :symbol) do |row|
  headers = row.headers unless headers
  values = [row[:surname], row[:post_code]]
  if set_one.include? values
    set_two << values
  else
    set_one << values 
  end
end

CSV.foreach('customers.csv', :headers => true, :header_converters => :symbol) do |row|
  values = [row[:surname], row[:post_code]]
  if set_two.include? values
    duplicates << row
  end
end

CSV.open("duplicate-customers.csv", "wb") do |csv|
  csv << headers
  duplicates.each { |dupe| csv << dupe }
end

【问题讨论】:

  • 将其放入mysql或sqlite之类的数据库中,然后运行SQL查询。可能是最灵活的。
  • @hakre 谢谢,我可能会不定期地运行脚本,使用新的 CSV 文件和不同的输入值,因此每次都创建数据库似乎并不明智。
  • 好吧,无论如何您可能都需要创建某种数据库。要么基于磁盘上的实际 CSV 文件(基于磁盘的数据库),要么基于内存中的数组(基于内存的数据库)。将 CSV 导入临时(可能在内存中)sqlite 数据库实际上对我来说并没有那么糟糕。
  • @hakre 你说得对,我可能是在找借口不使用任何 SQL!

标签: php ruby arrays algorithm csv


【解决方案1】:

让我们先读入csv(不处理转义或引号,只是一个例子)

csv = []
columns = []
File.read('csv.file') do |row|
  if csv.empty?
    columns=row.split(',')
  else
    row_data={}
    row.split(',').each_with_index do |c,i|
      row_data[columns[i]] = c
    end
    csv << row_data
  end
end

好的,我们如何处理数据?它看起来像:

[{'surname' => 'smith', 'postcode' => '1234', 'otherstuff' => 'xyz' },
 {'surname' => 'jones', 'postcode' => '1234', 'otherstuff' => 'xyz' },
 {'surname' => 'smith', 'postcode' => '2345', 'otherstuff' => 'xyz' },
 {'surname' => 'smith', 'postcode' => '1234', 'otherstuff' => 'xyz' }]

怎么样:

csv.select do |c| 
  csv.any? do |s| 
    s['surname'].eql?(c['surname']) && s['postcode'].eql?(c['postcode']) 
  end
end

好吧,这很慢而且不聪明。让我们继续解决方案 2,从我们要检查唯一性的数据中生成一个哈希键:

sneakyhash={}
csv.each do |row|
  magic_string = [row['surname'], row['postcode']].join("--MaGiCaL--SpLiTTinG--StRiNG--")
  if sneakyhash[magic_string].nil?
    sneakyhash[magic_string] = 1
  else
    puts "this guy looks suspicious: " + row.join(,)
  end
end

远非最佳,但只是在这里大声思考。如果这是一种“一次性”的事情,而您只需要解析一个文件,请使用您能想到的。

您可能想要做的是在读取 csv 时将此标识字符串存储在数组或哈希中,并查看当前行是否与存储的任何唯一行匹配,如果匹配,则执行某些操作。

【讨论】:

  • 谢谢,这让我发笑!你让我走上正轨。我需要保留对整行的引用,包括其他列(不需要重复),这样我就可以将每条记录(包括第一条)包含在重复的 csv 中。查看我的编辑以了解我现在的位置。
猜你喜欢
  • 1970-01-01
  • 2019-03-17
  • 2016-06-12
  • 2014-04-20
  • 2018-02-07
  • 1970-01-01
  • 1970-01-01
  • 2020-02-19
  • 1970-01-01
相关资源
最近更新 更多