【问题标题】:How do I compare two CSVs and remove a row if a key matches in ruby?如果键在 ruby​​ 中匹配,如何比较两个 CSV 并删除一行?
【发布时间】:2021-10-06 20:58:00
【问题描述】:

原谅我,因为我对 ruby​​ 很陌生,但我有两个 CSV,我想比较两个 CSV 文件,如果 CSV2 中的某些内容与 CSV1 中的键匹配,我想从 CSV1 中删除该行

CSV(包含大量编辑)例如:

# csv1

xyz_id,first_nm,last_nm
100001,Person,one
200002,Person,two
300003,Person,three
400001,Person,four
500001,Person,five
#csv2

id,name,first_name,last_name,address .....
1234,person,wun
1235,person,tuh who
1236,person,tree
100001,Person,one

如果在 csv2 中有匹配的内容,请从 CSV1 中删除整行。

这是我尝试过的:

我在另一个问题中看到我可以利用 delete_if 的用法,但我对它的实现有点困惑。但是,这是我的代码:

csv1 = CSV.table('./csv/csv1.csv', headers: true)
csv2 = CSV.table('./csv/csv2.csv', headers: true)

csv1.delete_if do |csv1row|
    csv2.each do |csv2row|
        csv1row[:xyz_id] == csv2[:id]
    end
end

我也不确定这是否有效。我必须写回csv1吗?或为此创建一个全新的 CSV?是否可以将其写回 csv1 如果 东西已被删除?

【问题讨论】:

  • 在给出任何示例时,基本规则是显示您想要返回的 Ruby 对象。 CSV 文件没有“密钥”。如果该行中任何字段的值等于第二个文件中任何行的相应字段的值,您的意思是要删除第一个文件中的该行吗?

标签: ruby csv


【解决方案1】:

您走在正确的道路上。 Array#delete_if 方法期望块返回一个布尔值。以 Ruby 文档中的这个例子为例:

scores = [ 97, 42, 75 ]
scores.delete_if {|score| score < 80 }   #=> [97]

在您的情况下,您只需将 Array#each 调用更改为 Array#any?。这将从csv1 中删除在csv2 中具有匹配ID 的行。

csv1.delete_if do |csv1row|
  csv2.any? { |csv2row| csv1row[:xyz_id] == csv2[:id] }
end

【讨论】:

  • 太棒了!我不知道 .any? 我需要再次通读 ruby​​docs ?。谢谢!!!
【解决方案2】:

首先使用下面的代码,它将两个 csv 文件加载到变量中,即带有标题的 csv1csv2。加载文件后,我们从csv1idcsv2 的列xyz_idid 的列中获取公共ID。如果 xyz_idcommon_ids 数组中可用,则从 csv1 删除重新编码。

csv1 = CSV.table('csv_1.csv', headers: true)
csv2 = CSV.table('csv_2.csv', headers: true)
common_ids = csv1[:xyz_id] & csv2[:id]
csv1.delete_if {|row| common_ids.include?(row[:xyz_id])}

【讨论】:

  • 谢谢你!当您执行common_ids = csv1[:xyz_id] &amp; csv2[:id] 时,我认为它会找到常见的ID,但是&amp; 通常会做什么?对于这个用例?
  • 正如我们所知的二进制&amp; 运算符,一旦两个数字都是1,否则返回数字1,否则返回0。在我们的例子中,数字是一个一个地检查另一个数组并只返回那些两个数组都可以使用的数字。
猜你喜欢
  • 1970-01-01
  • 2019-01-09
  • 2021-03-01
  • 2010-10-14
  • 2010-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多