Давайте создадим файл.
fname = 't'
IO.write fname, <<~END
dog
cat
dog
pig
cat
END
#=> 20
См. IO :: write . Сначала давайте предположим, что вы просто хотите прочитать уникальные строки в массив.
Если, как здесь, файл не слишком большой, вы можете написать:
arr = IO.readlines(fname, chomp: true).uniq
#=> ["dog", "cat", "pig"]
См. IO :: readlines . chomp: true
удаляет символ новой строки в конце каждой строки.
Если вы хотите sh, чтобы записать этот массив в другой файл:
fname_out = 'tt'
IO.write(fname_out, arr.join("\n") << "\n")
#=> 12
или
File.open(fname_out, 'w') do |f|
arr.each { |line| f.puts line }
end
Если вы хотите sh перезаписать 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"}>
См. IO :: foreach .
Если вы просто хотите sh записать содержимое этого набора в файл, вы можете выполнить:
File.open(fname_out, 'w') do |f|
st.each { |s| f.puts(s) }
end
Если вместо этого вы необходимо преобразовать набор в массив:
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"]
Если у вас недостаточно памяти, чтобы даже удерживать st
, вам нужно будет прочитать ваш файл (построчно) в базу данных, а затем использовать операции с базой данных.
Если вы хотите sh написать файл с пропущенными дубликатами, а файл очень большой, вы можете сделать следующее, хотя и с бесконечно малым риском включения одного или нескольких дубликатов (см. комментарии).
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}
$. - номер (основание 1) только что прочитанной строки. См. Строка # га sh. Поскольку число различных значений, возвращаемых этим методом, конечно, а число возможных строк бесконечно, существует вероятность, что две различные строки могут иметь одинаковое значение ha sh.
Тогда (при условии line_map
не является пустым):
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
См. Файл :: open .
Между прочим, для IO
методов класса m
(включая read
, write
, readlines
и foreach
), вы можете увидеть IO.m...
написано File.m...
. Это допустимо, потому что File
является подклассом IO
и поэтому наследует методы последнего. Это не относится к моему использованию File::open
, так как IO :: Open - это другой метод.