Ruby:如何从文档文本中删除重复行?

Ruby:如何从文档文本中删除重复行?,ruby,line,Ruby,Line,我想删除文本中的重复行,例如: 1.aabba 2.abaab 3.aabba 4.aabba 1.aabba 2.abaab 3.aabba 4.aabba 运行后: 1.aabba 2.abaab 迄今为止: lines = File.readlines("input.txt") lines = File.read('/path/to/file') lines.split("\n").uniq.join("\n") Set仅存储唯一元素,因此: require 'Set' s =

我想删除文本中的重复行,例如:

1.aabba
2.abaab
3.aabba
4.aabba
1.aabba
2.abaab
3.aabba
4.aabba
运行后:

1.aabba
2.abaab
迄今为止:

lines = File.readlines("input.txt")
lines = File.read('/path/to/file')
lines.split("\n").uniq.join("\n")

Set
仅存储唯一元素,因此:

require 'Set'

s = Set.new
while line = gets
  s << line.strip
end
s.each { |unique_elt| puts unique_elt }
require'Set'
s=设置为新
而line=get

让我们构造一个文件

fname = 't'

IO.write fname, <<~END
dog
cat
dog
pig
cat
END
  #=> 20
chomp:true
删除每行末尾的换行符

如果希望随后将该数组写入另一个文件:

fname_out = 'tt'
IO.write(fname_out, arr.join("\n") << "\n")
  #=> 12
如果要覆盖
fname
,请写入新文件,删除现有文件,然后重命名新文件
fname

如果文件太大,无法保存在内存中,并且有许多重复行,则可以执行以下操作

require 'set'

st = IO.foreach(fname, chomp: true).with_object(Set.new) do |line, st|
  st.add(line)
end
  #=> #<Set: {"dog", "cat", "pig"}>
如果需要将集合转换为数组:

st.to_a
  #=> ["dog", "cat", "pig"]
这假设您有足够的内存来存放
st
st.to_a
。如果没有,你可以写:

st.size.times.with_object([]) do |_,a|
  s = st.first
  a << s
  st.delete(s)
end
  #=> ["dog", "cat", "pig"]
是刚刚读取的行的编号(以1为基数)。看见由于此方法返回的不同值的数量是有限的,并且可能的字符串的数量是无限的,因此两个不同的字符串可能具有相同的哈希值

然后(假设
line\u map
不是空的):

让我们看看我们写了什么:

puts File.read(fname_out)
dog
cat
pig


顺便提一下,对于
IO
类方法
m
(包括
read
write
readlines
foreach
),您可以看到
IO.m.
writed
File.m.
。这是允许的,因为
File
IO
的子类,因此继承了后者的方法。这不适用于我使用的
File::open
,因为这是另一种方法。

您可以使用
uniq
继续您的想法

比较块的结果并删除重复项

例如,您有带有以下内容的
input.txt


此处删除列表编号,但您可以使用其他方法,例如
行[2..-1]

请包含您迄今为止尝试的代码我已编辑了代码不清楚前导行号是文本的一部分还是仅用于说明。啊,但在回答一个没有被很好地问到的问题之前还不算晚。记住,“我们”回答的问题很好请阅读“”及其链接页面。清晰对我们帮助您很重要。另一个提示:如果行非常大,请使用
集合
,但对每行(例如SHA2-256)进行散列,以避免存储整行。@tadman,谢谢您的建议。我编辑了我的答案以涵盖它。事实上,我以前考虑过将其包括在内,但决定不包括在内,因为重复的行可能会被重复。在这种情况下,我总是想到这一点,因为我唯一的商业编程任务就是编写一个通过电话线(后来是互联网)运行的计算机备份程序。为了避免传输我们库中已经存在的文件,我在用户端为每个新的或更改的文件计算了一个哈希代码,然后对照我们服务器的数据库对它们进行检查。是的,这就像在内部实现了一个非常基本的版本。使用一些散列和一个查找表可以做的事情令人惊讶。
st.size.times.with_object([]) do |_,a|
  s = st.first
  a << s
  st.delete(s)
end
  #=> ["dog", "cat", "pig"]
require 'set'

line_map = IO.foreach(fname, chomp: true).with_object({}) do |line,h|
  hsh = line.hash
  h[hsh] = $. unless h.key?(hsh)
end
  #=> {3393575068349183629=>1, -4358860729541388342=>2,
  #    -176447925574512206=>4} 
lines_to_keep = line_map.values 
File.open(fname_out, 'w') do |fout|
  IO.foreach(fname, chomp: true) do |line|
    if lines_to_keep.first == $.
      fout.puts(line)
      lines_to_keep.shift
    end
  end
end
puts File.read(fname_out)
dog
cat
pig
1.aabba
2.abaab
3.aabba
4.aabba
puts File.readlines('input.txt', chomp: true).
  uniq { |line| line.sub(/\A\d+\./, '') }.
  join("\n")

# will print
# 1.aabba
# 2.abaab