2

テキストファイルをメモリに読み込むと、新しい行があるため、最後に「\n」が付いたテキストが表示されます。

["Hello\n", "my\n", "name\n", "is\n", "John\n"] 

これが私がテキストファイルを読んでいる方法です

array = File.readlines('text_file.txt')

このテキスト配列で多くの処理を行う必要があるため、最初に配列を作成するときに「\ n」を削除する必要があるのか​​、それとも正規表現を使用して各要素で処理を行うのか、パフォーマンスの面で疑問に思っています。

「\n」を削除するためにいくつかの(明らかに悪い)テストコードを書きました

array = []
File.open('text_file.txt', "r").each_line do |line|
    data = line.split(/\n/)
    array << data
end
array.flatten!

アレイを最初に作成するときに「\n」を削除する必要がある場合、これを行うためのより良い方法はありますか?

代わりに(パフォーマンスのために)ファイルをセットに読み込みたい場合、それを行うためのreadlinesに似た方法はありますか?

4

5 に答える 5

4

Rubyの組み込みベンチマークを使用してベンチマークテストを実行し、最速の選択肢を見つける必要があります。

ただし、経験から、ファイルを「スラップ」する、つまり一度にすべてを読み込むことは、IO.foreachまたはFile.foreachでループを使用するよりも速くないことがわかりました。これは、Rubyと基盤となるOSが読み取りの発生時にファイルのバッファリングを実行し、ディスクから直接ではなくメモリからループを発生させるためです。foreachのようにラインターミネータを削除しないので、またはsplitを追加する必要があります。または、読み込まれた行を変更する場合は、次のように入力します。chompchomp!

File.foreach('/path/to/file') do |li|
  puts li.chomp
end

また

File.foreach('/path/to/file') do |li|
  li.chomp!
  puts li
end

また、丸呑みにはスケーラブルではないという問題があります。メモリよりも大きいファイルを読み取ろうとして、マシンをひざまずかせてしまう可能性がありますが、行ごとに読み取ることはできません。


パフォーマンスの数値は次のとおりです。

#!/usr/bin/env ruby

require 'benchmark'
require 'fileutils'

FILENAME = 'test.txt'
LOOPS = 1

puts "Ruby Version: #{RUBY_VERSION}"
puts "Filesize being read: #{File.size(FILENAME)}"
puts "Lines in file: #{`wc -l #{FILENAME}`.split.first}"

Benchmark.bm(20) do |x|
  x.report('read.split')           { LOOPS.times { File.read(FILENAME).split("\n") }}
  x.report('read.lines.chomp')     { LOOPS.times { File.read(FILENAME).lines.map(&:chomp) }}
  x.report('readlines.map.chomp1') { LOOPS.times { File.readlines(FILENAME).map(&:chomp) }}
  x.report('readlines.map.chomp2') { LOOPS.times { File.readlines(FILENAME).map{ |s| s.chomp } }}
  x.report('foreach.map.chomp1')   { LOOPS.times { File.foreach(FILENAME).map(&:chomp) }}
  x.report('foreach.map.chomp2')   { LOOPS.times { File.foreach(FILENAME).map{ |s| s.chomp } }}
end

そして結果:

Ruby Version: 1.9.3
Filesize being read: 42026131
Lines in file: 465440
                           user     system      total        real
read.split             0.150000   0.060000   0.210000 (  0.213365)
read.lines.chomp       0.470000   0.070000   0.540000 (  0.541266)
readlines.map.chomp1   0.450000   0.090000   0.540000 (  0.535465)
readlines.map.chomp2   0.550000   0.060000   0.610000 (  0.616674)
foreach.map.chomp1     0.580000   0.060000   0.640000 (  0.641563)
foreach.map.chomp2     0.620000   0.050000   0.670000 (  0.662912)

今日のマシンでは、42MBのファイルをRAMにかなり安全に読み込むことができます。一部の本番ホストのメモリに収まらないファイルよりもはるかに大きいファイルを見たことがあります。速度は遅くなりますがforeach、十分なメモリがない場合は、すべてのメモリを吸い上げてマシンをひざまずかせることもありません。

Ruby 1.9.3ではmap(&:chomp)、古い形式のの代わりにメソッドを使用する方map { |s| s.chomp }がはるかに高速です。これは古いバージョンのRubyには当てはまらなかったので、エンプターに注意してください。

また、上記のすべてが私の数年前のMacProで1秒未満でデータを処理したことに注意してください。全体として、ロード速度を心配するのは時期尚早の最適化であり、本当の問題はデータがロードされた後に何が行われるかということです。

于 2012-09-13T18:29:47.780 に答える
4

String#chompを使用します:

lines = open('text_file.txt').lines.map(&:chomp)
于 2012-09-13T18:35:00.247 に答える
0

このような場合は、分割よりもストリップを使用し、初めてラインを処理した直後に使用することをお勧めします。readlineの後にsplitを使用するのは、過剰なimoです。したがって、コードスニペットは次のようになります。

array = []
File.open('text_file.txt', "r").each_line do |line|
    array << data.strip
end
于 2012-09-13T18:33:55.737 に答える
0

末尾の改行文字を削除する場合は、 String#chompまたはString# rstripのいずれかを使用できます。私の好みの方法はchompです。

したがって、次のようなことを簡単に行うことができます。

lines.map! { |line| line.chomp }
# or
lines.map! { |line| line.rstrip }
于 2012-09-13T18:35:08.297 に答える
0
mvelez@argo:~$ cat test.txt
Hello
my
name
is
John

一発ギャグ:

arr = File.open("test.txt",'r').read.split

これを分解するirb

irb(main):002:0> f = File.open("test.txt",'r')
=> #<File:test.txt>
irb(main):003:0> file_contents = f.read
=> "Hello\nmy\nname\nis\nJohn\n\n"
irb(main):004:0> file_contents.split
=> ["Hello", "my", "name", "is", "John"]
于 2012-09-13T18:39:03.147 に答える