Two lists of dictionaries. Dicts in A and B can be matched by a particular dict key that may be identical or similar. The result should be a list of the source key from A, the matching key from B, and an additional key from B.
Both lists are constructed using screen-scraping, so you normally don't get to see them (unless you print
them explicitly). For clarity though: list A is called stoxlist
and looks something like this:
stoxlist = [{'stock': 'Apple',
'last_price': afloat,
'some-more': 'value',
..
},
{'stock': 'Google',
'last_price': afloat,
'some-more': 'value',
..
},
...
]
List B looks like this:
symbollist = [{'name': 'Apple', 'symbol': 'APPLE'},
{'name': 'Google', 'symbol': 'ALPHABET'},
...
]
The following does what it should do. Using Python 2.7.
# lookup helpers
def match(this, that):
''' returns True if this loosely matches with that '''
if this.strip('.') in that or this.split()[0] in that:
return True
else:
return False # this is not necessary, but explicit is better than implicit.
def fetch(name, symbols, key):
''' find name by dict[key] in list of dicts symbols '''
return next((item for item in symbols if match(name, item[key])), None)
def adddict(entry, symbol):
dict = {'source' : entry['stock'],
'found' : symbol['name'],
'symbol' : symbol['symbol']}
return dict
def lookup(stox, symbols):
'''lookup symbol for stock name'''
hits = []
misses = []
for entry in stox:
# try an exact match first
sym = next((item for item in symbols if entry['stock'] == item['name']), None)
try:
# save a hit, if any
hits.append(adddict(entry, sym))
except TypeError:
# if not, try a looser match
sym = fetch(entry['stock'], symbols, 'name')
try:
hits.append(adddict(entry, sym))
except TypeError:
# try yet another possibility
sym = fetch(entry['stock'].upper(), symbols, 'symbol')
try:
hits.append(adddict(entry, sym))
except TypeError:
# lastly try one of the hardcoded SPECIALS.
sym = fetch(entry['stock'], SPECIALS, 'name')
try:
hits.append(adddict(entry, sym))
except TypeError:
misses.append(entry['stock'])
return hits, misses
def main():
# load_all loads a pickle, made by some other module
stoxlist = load_all()
# get_symlist is a screen-scraper, using BeautifulSoup.
symbollist, nosyms = get_symlist()
hits, misses = lookup(stoxlist, symbollist)
I think try-except
makes for better readability than if-elif
. But it's four levels deep, which is not pretty.
There are four full iterations over list B (symbols
) for every entry in list A (stox
). That's not pretty either. Yet I can't think of any better way, because it is necessary to first try an ==
on all items in B, then a looser match on all items in B, and so on.
I'm not really bothered by performance yet. The lists aren't big, less than 100 items each. But perhaps it could all be done much more efficiently/elegantly/Pythonically if I chose a different data structure than list of dicts?
Please comment.