从CSV删除重复项-性能问题

时间:2019-08-09 20:32:14

标签: performance crystal-lang

我有一个看起来像这样的CSV文件:

foo,bar,glib
"a","1","A"
"b","1","B"
"a","2","C"
"b","1","D"

我正在遍历该CSV文件,并想删除foobar相同的所有重复行,即,我生成的文件应如下所示:

foo,bar,glib
"a","1","A"
"b","1","B"
"a","2","C"

这就是我的做法:

require "csv"

File.open("input.csv") do |infile|
  reader = CSV.new(infile, header=true)
  File.open("output.csv", "w") do |outfile|
    printed_tuples = Array(Tuple(String, String)).new
    CSV.build(outfile) do |writer|
      while reader.next
        next if printed_tuples.includes?({reader.row["foo"], reader.row["bar"]})
        printed_tuples << {reader.row["foo"], reader.row["bar"]}
        writer.row reader.row.to_a
      end
    end
  end
end

真正的CSV文件要大得多(386280行和17列),而且速度太慢以至于几乎无法使用。

具有讽刺意味的是,我一直在重写python脚本,因为我曾希望能获得更好的性能,但现在python版本要快得多。

有人对如何加快速度有任何指示吗?

1 个答案:

答案 0 :(得分:5)

关键操作是搜索现有值。 Array#includes?在这种情况下效率很低:它需要遍历所有先前的行(对于重复的行,不是全部,而是通常其中的一半)。为每一行执行该操作,即O(N²)

您需要一个可以更快搜索的不同数据结构。 Crystal具有Set类型,该类型由哈希表支持。

也许有更好的数据结构和算法可以解决此问题,但是Set在Crystal的标准库中可用,应该已经做了很多改进。