2013-04-11 2 views
1

У меня есть скрипт python, данный шаблон просматривает файл, и для каждой строки, которая соответствует шаблону, он подсчитывает, сколько раз эта строка отображается в файле.Подсчитайте строки, соответствующие различным шаблонам за один проход

Сценарий следующий:

#!/usr/bin/env python 

import time 
fnamein = 'Log.txt' 

def filter_and_count_matches(fnamein, fnameout, match): 
    fin = open(fnamein, 'r') 
    curr_matches = {} 
    order_in_file = [] # need this because dict has no particular order 
    for line in (l for l in fin if l.find(match) >= 0): 
    line = line.strip() 
    if line in curr_matches: 
     curr_matches[line] += 1 
    else: 
     curr_matches[line] = 1 
     order_in_file.append(line) 
    # 
    fout = open(fnameout, 'w') 
    #for line in order_in_file: 
    for line, _dummy in sorted(curr_matches.iteritems(), 
     key=lambda (k, v): (v, k), reverse=True): 
    fout.write(line + '\n') 
    fout.write(' = {}\n'.format(curr_matches[line])) 
    fout.close() 

def main(): 
    for idx, match in enumerate(open('staffs.txt', 'r').readlines()): 
    curr_time = time.time() 
    match = match.strip() 
    fnameout = 'm{}.txt'.format(idx+1) 
    filter_and_count_matches(fnamein, fnameout, match) 
    print 'Processed {}. Time = {}'.format(match, time.time() - curr_time) 

main() 

Так прямо сейчас я иду на файл каждый раз, когда я хочу, чтобы проверить на другой шаблон. Можно сделать это, перейдя по файлу только один раз (файл довольно большой, так что требуется некоторое время для обработки). Было бы неплохо иметь возможность сделать это элегантным «легким» способом. Благодаря!

Благодаря

+0

Не ответ на ваш вопрос, но 'grep', вероятно, будет более полезным здесь, если это на самом деле конечная цель для вашей проблемы. –

ответ

2

Похоже Counter бы делать то, что вам нужно:

from collections import Counter 
lines = Counter([line for line in myfile if match_string in line]) 

Например, если myfile содержит

123abc 
abc456 
789 
123abc 
abc456 

и match_string является "abc", то приведенный выше код дает вам

>>> lines 
Counter({'123abc': 2, 'abc456': 2}) 

Для нескольких моделей, как об этом:

patterns = ["abc", "123"] 
# initialize one Counter for each pattern 
results = {pattern:Counter() for pattern in patterns} 
for line in myfile: 
    for pattern in patterns: 
     if pattern in line: 
      results[pattern][line] += 1 
+0

Я попробовал, и счетчик кажется намного быстрее, чем мой подход. Проблема в том, что, поскольку у меня есть разные шаблоны, которые я хочу подсчитать, мне все равно придется перебирать файл для каждого из этих шаблонов. Это то, что я пытаюсь избежать в этот момент. Есть идеи по этому поводу? – skeept

+0

@skeept: Вам нужен дополнительный счетчик для каждого шаблона или один счетчик для всех матчей? –

+0

один счетчик для каждого образца. Это то, что делает код сейчас (он сохраняет число, которое каждый patter появляется в файле, соответствующем этому шаблону), но он просматривает файл один раз за шаблон, я бы хотел этого избежать. – skeept

Смежные вопросы