2014-01-15 4 views
1

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

Файл 1

0: 152 145 148 
1: 251 280 428 
2: 42 281 407 
3: 289 292 331 
4: 309 212 226 
5: 339 336 376 
6: 339 376 380 
7: 41 406 205 
8: 237 418 193 

Файл 2

0: 251 280 428 
1: 309 212 226 
2: 339 336 376 
3: 339 376 380 
4: 420 414 199 
5: 418 193 237 
6: 203 195 200 
7: 287 161 257 
8: 287 257 158 
9: 263 369 15 
10: 285 323 327 

Первый столбец только серийные номера и должны игнорироваться при проверке соответствия между два файла и набор одинаковых номеров с различным порядком следует считать общим (for e.g 237 418 193 = 418 193 237)

В этом случае ожидаемый результат будет .....

5 # no. of common sets 
251 280 428 
309 212 226 
339 336 376 
339 376 380 
237 418 193 

Я попытался с AWK сценария -

awk 'FNR==NR{a[$3]=$0;next}{if(b=a[$3]){print b}}' file1 file2 

К сожалению, набор "237 418 193" не счет, так как он имеет другой порядок во втором файле (418 193 237).

Может ли кто-нибудь помочь мне выполнить эту задачу с помощью сценария awk или Python.

Любая помощь приветствуется?

+0

Хитрость заключается в сортировке каждого набора путем увеличения значений для стандартизации заказа. –

+0

Я написал сценарий некоторое время назад, чтобы помочь мне работать с строками файла в виде наборов. Код находится по адресу https://github.com/nibrahim/lines. Похоже, вы сможете использовать его после некоторой предварительной обработки (потеря серийных номеров). –

ответ

0

Попробуйте этот питон код:

data1, data2 = [], [] 
for fname, data in [('file1.txt', data1), ('file2.txt', data2)]: 
    for line in open(fname): 
     data.append(set(line.strip().split()[1:])) 

common = [s for s in data1 if s in data2] 
for c in common: 
    print c 
print len(common) 

Выход:

set(['280', '251', '428']) 
set(['309', '212', '226']) 
set(['336', '339', '376']) 
set(['380', '339', '376']) 
set(['237', '418', '193']) 
5 
1

Разбираем файл, создавая set линий, каждый элемент сортируется лексикографически.

file1_sets = {tuple(sorted(line.split()[1:])) for line in open(file1, 'r')} 
file2_sets = {tuple(sorted(line.split()[1:])) for line in open(file2, 'r')} 

Тогда посмотрим, сколько одного существует в другой

count = sum([f in file2_sets for f in file1_sets]) 

(Под редакцией за комментарии)

+0

Вы не должны включать идентификаторы (первый столбец файлов) в свои наборы – Daniel

+0

@ Даниэль спасибо, исправлено – mhlester

+0

У меня есть ненужные дополнения здесь - __f в file2_sets для f в file1_sets__ будет делать работу – volcano

0

Использование наборов и .intersection:

with open("21132195_1.txt") as fh1, open("21132195_2.txt") as fh2: 
    number_sets1 = set(frozenset(line.split()[1:]) for line in fh1) 
    number_sets2 = set(frozenset(line.split()[1:]) for line in fh2) 

common_number_sets = number_sets1.intersection(number_sets2) 

print "%i # no. of common sets" % len(common_number_sets) 
print "\n".join([" ".join(s) for s in common_number_sets]) 

даст в качестве вывода:

5 # no. of common sets 
339 376 380 
251 280 428 
212 226 309 
193 237 418 
336 339 376 
+0

Мне просто интересно - зачем вам звонить на _sorted_ и _tuple_? – volcano

+0

'sorted' необходим для сортировки всех строк по возрастанию и для обработки различного порядка чисел. 'tuple' необходим, поскольку в наборах могут использоваться только хешируемые объекты, а полученный« list »не является хешируемым. –

+0

Простите, что – volcano

0

В Gnu Awk версии 4.1, вы можете использовать PROCINFO["sorted_in"] как:

gawk -f c.awk file1 file2 

где c.awk является:

BEGIN {PROCINFO["sorted_in"]="@val_num_asc"} 
NR==FNR { 
    b[getRow()]++ 
    next 
} 
{ 
    c=getRow() 
    if (c in b) 
     a[++j]=c 
} 
END{ 
    print j" # no. of common sets" 
    for (i in a) 
     print a[i] 
} 

function getRow(b,d,i) { 
    for (i=2; i<=NF; i++) 
     d[i]=$i 
    for (i in d) 
     b=(b=="")?d[i]:(b" "d[i]) 
    return b 
} 

Выход:

5 # no. of common sets 
193 237 418 
212 226 309 
251 280 428 
336 339 376 
339 376 380 
+0

спасибо за помощь. Но когда я использовал для разных входных файлов (с аналогичным форматом файлов, как раньше), программа дает неверный вывод. Предположим, что он найдет 7 общих наборов, но на выходе отображается только 5 из них. – user3138998

+0

@ user3138998 Можете ли вы вставить входные файлы по адресу http://pastebin.com/? Тогда я проверю это. –

0

Другой способ использования оболочки.

cat file1 file2 |while read x line 
do 
    arr2=($(for val in $line;do echo "$val";done|sort -n)) 
    echo "${arr2[@]}" 
done|awk '++a[$1,$2,$3]>1' 

251 280 428 
212 226 309 
336 339 376 
339 376 380 
193 237 418 
Смежные вопросы