существует ли способ отобразить строки, содержащие определенные строки (как почтительный::: N в примере ниже), которые не происходят в течение времен N в определенном файле?
Я знаю, что могу считать возникновение некоторой строки с grep
, запишите это в новый файл и затем считайте строки с wc -l
. Однако у меня есть огромный файл, где я должен отфильтровать строки, где строка в столбце 1 не появляется 5 раз в столбце 1 файла.
Предложения очень ценятся.
редактирование строки в file_1.txt в алфавитном порядке отсортировано по первому столбцу. Файл содержит приблизительно 1 000 000 строк, я мог также разломать его на несколько маленьких файлов, конечно. Порядок вывода не имеет значения.
file_1.txt
realism:::N 1.33 depth:::N 3.11 341
realism:::N 1.33 problem:::N 2.68 335
realism:::N 1.33 now:::ADV 1.48 335
realism:::N 1.33 life:::N 2.69 334
renowned:::ADJ 1.41 be:::V 1.85 15760
renowned:::ADJ 1.41 internationally:::ADV 2.23 9134
renowned:::ADJ 1.41 world:::N 4.36 6736
renowned:::ADJ 1.41 most:::ADV 2.38 5482
reverent:::ADJ 1.5 use:::V 2.78 25
reverent:::ADJ 1.5 sacred:::ADJ 1.77 25
reverent:::ADJ 1.5 music:::N 4.31 25
reverent:::ADJ 1.5 devout:::ADJ 2.46 25
reverent:::ADJ 1.5 devotion:::N 2.36 25
output_file.txt
reverent:::ADJ 1.5 use:::V 2.78 25
reverent:::ADJ 1.5 sacred:::ADJ 1.77 25
reverent:::ADJ 1.5 music:::N 4.31 25
reverent:::ADJ 1.5 devout:::ADJ 2.46 25
reverent:::ADJ 1.5 devotion:::N 2.36 25
awk
со справкой от замены процесса (<()
), sort
, и uniq
:
awk 'NR==FNR{a[$0]; next} {for (i in a) if ($1==i) {print}}' \
<(awk '{print $1}' file.txt | sort| uniq -c | awk '$1 >= 5 {print $2}') file.txt
awk '{print $1}' file.txt | sort| uniq -c | awk '$1 >= 5 {print $2}'
получает первые поля, где содержание происходит больше, чем или равный 5 разам. Замена команды, <()
, заменяет STDOUT дескриптором файла, который передается как первый аргумент основному рабочему awk
процесс, с исходным входным файлом как второй
NR==FNR{a[$0]; next}
создает массив a
с элементами из первого файла (NR==FNR
) как ключи
{for (i in a) if ($1==i) {print}}'
печатает строки от file.txt
это имеет ключи от массива a
как первое поле
Очевидный протест состоит в том, что этот подход читает файл дважды, который не мог бы быть оптимальным решением для большого (в обычном определении) входной файл, где высокая скорость и/или низкое использование ресурсов ожидаются.
Пример:
% cat file.txt
realism:::N 1.33 depth:::N 3.11 341
realism:::N 1.33 problem:::N 2.68 335
realism:::N 1.33 now:::ADV 1.48 335
realism:::N 1.33 life:::N 2.69 334
renowned:::ADJ 1.41 be:::V 1.85 15760
renowned:::ADJ 1.41 internationally:::ADV 2.23 9134
renowned:::ADJ 1.41 world:::N 4.36 6736
renowned:::ADJ 1.41 most:::ADV 2.38 5482
reverent:::ADJ 1.5 use:::V 2.78 25
reverent:::ADJ 1.5 sacred:::ADJ 1.77 25
reverent:::ADJ 1.5 music:::N 4.31 25
reverent:::ADJ 1.5 devout:::ADJ 2.46 25
reverent:::ADJ 1.5 devotion:::N 2.36 25
% awk 'NR==FNR{a[$0]; next} {for (i in a) if ($1==i) {print}}' <(awk '{print $1}' file.txt | sort| uniq -c | awk '$1 >= 5 {print $2}') file.txt
reverent:::ADJ 1.5 use:::V 2.78 25
reverent:::ADJ 1.5 sacred:::ADJ 1.77 25
reverent:::ADJ 1.5 music:::N 4.31 25
reverent:::ADJ 1.5 devout:::ADJ 2.46 25
reverent:::ADJ 1.5 devotion:::N 2.36 25
Так как Вы упоминаете, что строки в алфавитном порядке отсортированы по первому столбцу:
Сценарий ниже считает строки, сохраняет их в буфере, пока строка запускается с той же строки в столбце один как предыдущий.
В противном случае буфер добавляется к выходному файлу (только), если количество строк встречает определенное значение, буфер впоследствии очищен, и процесс запускается снова, пока файл не сделан.
Это должно быть довольно быстро на больших файлах, хотя я не запускал тест времени (еще) на огромных файлах
#!/usr/bin/env python3
import sys
#-- set the minimum number below
n = 5
# don't change anything below
f = sys.argv[1]; out = sys.argv[2]; mark1 = ""; lines = []
def write_out(lines):
if len(lines) >= n:
with open(out, "a+") as wrt:
for line in lines:
wrt.write(line)
with open(f) as read:
for l in read:
mark2 = l.split()[0]
if mark2 == mark1:
lines.append(l)
else:
write_out(lines)
lines = [l]
mark1 = mark2
# add the last set of lines
write_out(lines)
get_lines.py
Выполните его с входным и выходным файлом как аргументы:
python3 /path/to/get_lines.py <input_file> <output_file>
Вывод (как ожидалось) в output_file
, если мы устанавливаем предел к 5:
reverent:::ADJ 1.5 use:::V 2.78 25
reverent:::ADJ 1.5 sacred:::ADJ 1.77 25
reverent:::ADJ 1.5 music:::N 4.31 25
reverent:::ADJ 1.5 devout:::ADJ 2.46 25
reverent:::ADJ 1.5 devotion:::N 2.36 25