Skip to content Skip to sidebar Skip to footer

Python: How To Check That If An Item Is In A List Efficiently?

I have a list of strings (words like), and, while I am parsing a text, I need to check if a word belongs to the group of words of my current list. However, my input is pretty big

Solution 1:

You might consider a trie or a DAWG or a database. There are several Python implementations of the same.

Here is some relative timings for you to consider of a set vs a list:

import timeit
import random

withopen('/usr/share/dict/words','r') as di:  # UNIX 250k unique word list 
    all_words_set={line.strip() for line in di}

all_words_list=list(all_words_set)    # slightly faster if this list is sorted...      

test_list=[random.choice(all_words_list) for i inrange(10000)] 
test_set=set(test_list)

defset_f():
    count = 0for word in test_set:
        if word in all_words_set: 
           count+=1return count

deflist_f():
    count = 0for word in test_list:
        if word in all_words_list: 
           count+=1return count

defmix_f():
    # use list for source, set for membership testing
    count = 0for word in test_list:
        if word in all_words_set: 
           count+=1return count    

print"list:", timeit.Timer(list_f).timeit(1),"secs"print"set:", timeit.Timer(set_f).timeit(1),"secs"print"mixed:", timeit.Timer(mix_f).timeit(1),"secs"

Prints:

list: 47.4126560688 secsset: 0.00277495384216 secsmixed: 0.00166988372803 secs

ie, matching a set of 10000 words against a set of 250,000 words is 17,085 X faster than matching a list of same 10000 words in a list of the same 250,000 words. Using a list for the source and a set for membership testing is 28,392 X faster than an unsorted list alone.

For membership testing, a list is O(n) and sets and dicts are O(1) for lookups.

Conclusion: Use better data structures for 600 million lines of text!

Solution 2:

I'm not clear on why you chose a list in the first place, but here are some alternatives:

Using a set() is likely a good idea. This is very fast, though unordered, but sometimes that's exactly what's needed.

If you need things ordered and to have arbitrary lookups as well, you could use a tree of some sort: http://stromberg.dnsalias.org/~strombrg/python-tree-and-heap-comparison/

If set membership testing with a small number of false positives here or there is acceptable, you might check into a bloom filter: http://stromberg.dnsalias.org/~strombrg/drs-bloom-filter/

Depending on what you're doing, a trie might also be very good.

Solution 3:

This uses list comprehension

words_in_line = [word for word in line if word in my_list]

which would be more efficient than the code you posted, though how much more for your huge data set is hard to know.

Solution 4:

There are two improvments you can make here.

  • Back your word list with a hashtable. This will afford you O(1) performance when you are checking if a word is present in your word list. There are a number of ways to do this; the most fitting in this scenario is to convert your list to a set.
  • Using a more appropriate structure for your matching-word collection.
    • If you need to store all of the matches in memory at the same time, use a dequeue, since its append performance is superior to lists.
    • If you don't need all the matches in memory at once, consider using a generator. A generator is used to iterate over matched values according to the logic you specify, but it only stores part of the resulting list in memory at a time. It may offer improved performance if you are experiencing I/O bottlenecks.

Below is an example implementation based on my suggestions (opting for a generator, since I can't imagine you need all those words in memory at once).

from itertools import chain
d = set(['a','b','c']) # Load our dictionary
f = open('c:\\input.txt','r')
# Build a generator to get the words in the file
all_words_generator = chain.from_iterable(line.split() for line in f)
# Build a generator to filter out the non-dictionary words
matching_words_generator = (word for word in all_words_generator if word in d)
for matched_word in matching_words_generator:
    # Do something with matched_wordprint matched_word
# We're reading the file during the above loop, so don't close it too early
f.close()

input.txt

ab dog cat
c dog poop
maybe b cat
dog

Output

ab
c
b

Post a Comment for "Python: How To Check That If An Item Is In A List Efficiently?"