UserNames、userID、その他のデータのリストを含むCSVファイルusers.csv
があります。
username, userid, sidebar_side, sidebar_colour
"John Lennon", 90123412, "left", "blue"
"Paul McCartny", 30923833, "left", "black"
"Ringo Starr", 77392318, "right", "blue"
"George Harrison", 72349482, "left", "green"
別のファイルtoremove.txt
に、userIDのリストがあります。
30923833
77392318
users.csv
のIDを含むtoremove.txt
ファイルからすべての行を削除するための賢明で効率的な方法はありますか? 2つのファイルを解析し、toremove.txt
にない行だけを新しいファイルに書き込む単純なPythonアプリを記述しましたが、非常に遅いです。おそらくいくつかのsed
またはawk
魔法がここで役立ちますか?
これは、上記の例を考慮すると、望ましい結果です。
username, userid, sidebar_side, sidebar_colour
"John Lennon", 90123412, "left", "blue"
"George Harrison", 72349482, "left", "green"
grep
を使用すると、次のことができます。
$ grep -vwF -f toremove.txt users.txt
username, userid, sidebar_side, sidebar_colour
"John Lennon", 90123412, "left", "blue"
"George Harrison", 72349482, "left", "green"
awk
の場合:
$ awk -F'[ ,]' 'FNR==NR{a[$1];next} !($4 in a)' toremove.txt users.txt
username, userid, sidebar_side, sidebar_colour
"John Lennon", 90123412, "left", "blue"
"George Harrison", 72349482, "left", "green"
スペースブラインドになるように変更されたGnoucのawk
の回答は次のとおりです。
awk -F, 'FNR==NR{a[$1];next} !(gensub("^ *","",1,$2) in a)' toremove.txt users.csv
区切り文字としてカンマ(スペースではなく)のみを使用しているため、$1
は"John Lennon"
、$2
は 90123412
(先頭にスペースを含む)などです。したがって、gensub
は、$2
ファイルにユーザーIDが含まれているかどうかを確認する前に、toremove.txt
から任意の数の先行スペースを削除します。
OK Ruby方法:ファイルに文字列のリストがあり、別のファイルからすべての行を削除したい場合contain最初の文字列ファイル(この場合、「file1」から「file2」を削除)Ruby file:
b=File.read("file2").split # subtract this one out
remove_regex = Regexp.new(b.join('|'))
File.open("file1", "r").each_line do |line|
if line !~ remove_regex
puts line
end
end
残念ながら、大きな「削除」ファイルを使用すると、これは複雑さの点でO(N ^ 2)に低下するように見えます(私の仮定は、正規表現にはやらなければならない作業がたくさんあることです)。完全な行を削除するだけではありません)。場合によってはより高速になることがあります。
速度を上げる場合の別のオプションは、同じハッシュチェックメカニズムを使用することですが、一致する可能性のある文字列の行を注意深く「解析」し、ハッシュと比較します。
Rubyでは、次のようになります。
b=File.read("file2").split # subtract this one out
hash={}
for line in b
hash[line] = 1
end
ARGF.each_line do |line|
ok = true
for number in line.scan(/\d{9}/)
if hash.key? number
ok=false
end
end
if (ok)
puts line
end
end
スコットの回答も参照してください。これは、これまでに提案されたawkの回答に類似しており、O(N ^ 2)の複雑さを回避します(phew)。