Hi All

I have two tab-delimited files. I want to compare first column of testfile1 to first column of testfile2 to find if items in file2 are in file1 and write it to the new file.

I have a following code but not working!! :(.

f1 = open('testfile1.txt')
#f2 = open('testfile2.txt')

for line in f1:
    a = line.split()
    list1 = a[0].split()
    print list1
print "now printing list 2"
    f2 = open('testfile2.txt')
    for line in f2:
        b = line.split()
        list2 = b[0].split()
        print list2
    
    for i,e1 in enumerate(list1):
        for e2 in (list2):
            if e2 in e1:
                print ("line %d : %s" % (i,e1))
            else:
                print"No matching entries"
             
f1.close()
f2.close()

Any helps?

Dani AI

Generated

A compact, beginner-friendly alternative is to read the files as TSV and use a set for fast membership tests. This keeps the logic simple (build set of keys from file1; stream file2 and write matches) and is O(n + m) instead of an O(n*m) nested loop. It follows the same idea behind 's dict lookup and 's set suggestion but uses the standard csv module to handle tabs and quoted fields cleanly.

import csv

def keys_from_tsv(path):
    with open(path, newline='') as f:
        return {row[0].strip() for row in csv.reader(f, delimiter='\t') if row}

keys = keys_from_tsv('testfile1.txt')

with open('testfile2.txt', newline='') as fin, open('common.txt', 'w', newline='') as fout:
    reader = csv.reader(fin, delimiter='\t')
    writer = csv.writer(fout, delimiter='\t')
    for row in reader:
        if row and row[0].strip() in keys:
            writer.writerow(row)

If file1 can contain duplicate keys that must be preserved (rather than treated as a single lookup key), store rows in a mapping of lists via collections.defaultdict(list) and then join each matching file2 row with all entries from file1.

For very large files that do not fit memory, use external sorting + the Unix join utility (both files must be sorted on the key):

sort -t $'\t' -k1,1 testfile1.txt > f1s
sort -t $'\t' -k1,1 testfile2.txt > f2s
join -t $'\t' -1 1 -2 1 f1s f2s > common.txt

Notes and pitfalls: trim whitespace and normalize case if needed, handle CRLF on Windows, and skip headers with next(reader, None) when present. The csv+set method is the simplest for modest file sizes; use join or a small DB (sqlite) for huge datasets.

Recommended Answers

All 6 Replies

Try this code, which uses list comprehensions

from pprint import pprint

def records(filename):
    """generates pairs (word, line) from the file, where word is the first column"""
    return ((line[:line.find('\t')], line) for line in open(filename))

L1 = list(records('testfile1.txt'))
D1 = dict(L1)

assert(len(L1) == len(D1)) # check that keys are unique in the first file.

pprint(D1)

result = [(word, line) for (word, line) in records('testfile2.txt') if word in D1]

pprint(result)

Try this code, which uses list comprehensions

from pprint import pprint

def records(filename):
    """generates pairs (word, line) from the file, where word is the first column"""
    return ((line[:line.find('\t')], line) for line in open(filename))

L1 = list(records('testfile1.txt'))
D1 = dict(L1)

assert(len(L1) == len(D1)) # check that keys are unique in the first file.

pprint(D1)

result = [(word, line) for (word, line) in records('testfile2.txt') if word in D1]

pprint(result)

Thanks a lot for the code.! Working very well.

Is there any other.. simple way to do it. as a beginner it seems bit complicated to rewrite the code on own.

Helps greatly appreciated!

Thanks a lot for the code.! Working very well.

Is there any other.. simple way to do it. as a beginner it seems bit complicated to rewrite the code on own.

Helps greatly appreciated!

Yes, you could write it this way

def records(filename):
    for line in open(filename):
        index = line.find('\t')
        word = line[:index]
        yield (word, line)

D1 = dict(records('testfile1.txt'))

for word, line in records('testfile2.txt'):
    if word in D1:
        # etc... do something

You should learn about the yield statement if you don't know it yet. It is very powerful !

You can split records from \t and put first records to set and then same from other file and for each record which is in second file which has same key field put in result. Gribouillis did nicely that he checked for uniqueness of the keys as text file is not database and does not enforce uniqueness.

It is good practise to make generators/list comprehensions as they are pythonic and efficient way of doing things. If you do not like them, you can change them to normal loops easy enough.

result = (line.split()
          for  key in set(line.split('\t',1)[0] for line in open('testfile1.txt'))
          for  line in open('testfile2.txt')
          if line.startswith(key+'\t')
          )
for same in sorted(result):
    print(same)

You can split records from \t and put first records to set and then same from other file and for each record which is in second file which has same key field put in result. Gribouillis did nicely that he checked for uniqueness of the keys as text file is not database and does not enforce uniqueness.

It is good practise to make generators/list comprehensions as they are pythonic and efficient way of doing things. If you do not like them, you can change them to normal loops easy enough.

result = (line.split()
          for  key in set(line.split('\t',1)[0] for line in open('testfile1.txt'))
          for  line in open('testfile2.txt')
          if line.startswith(key+'\t')
          )
for same in sorted(result):
    print(same)

Fantastic!!!!!!!! easy and worked so welll.. ! perfect.

Thank you all!

Notice though that after the loop the result generator is empty. If you need the values many times change result from generator to list comprehension by changing outer () to [].

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.