Full Script
import copy
'''
Aggregators are used with the group function
'''
def list_aggregator(agg, item):
if agg ==None:return [item]
agg.append(item)
return agg
def count_aggregator(agg, item):
if agg == None: return 1
return agg+1
'''
group will take a list of dictionaries and build a dictionary out of it, where the keys are the values specified by the
keys input.
'''
def group(items, keys, aggregator=list_aggregator):
map = {}
for item in items:
current = map
if callable(keys):
keys2 = keys(item)
if not isinstance(keys2, list): keys2 = [keys2]
else:
keys2 = [item[key] for key in keys]
while len(keys2)>0:
key = keys2.pop(0)
if len(keys2) == 0:
if key in current:
current[key] = aggregator(current[key], item)
else:
current[key] = aggregator(None, item)
else:
if key not in current:
current[key] = {}
current = current[key]
pass
pass
return map
'''
to_list is used with a dictionary created by the group function to flatten the results into a list of dictionaries
'''
def to_list(cols, group):
results = []
if len(cols) == 1:
name = cols[0]
if isinstance(group, dict):
for key in group:
val = group[key]
if isinstance(val, list):
for item in val:
item = copy.deepcopy(item)
item[name] = key
results.append(item)
pass
pass
else:
record = {}
record[name] = key
results.append(record)
pass
pass
pass
else:
item = {}
item[name] = group
results.append(item)
pass
return results
name = cols[0]
ncols = cols[1:]
for key in group:
group2 = group[key]
results2 = to_list(ncols, group2)
for item in results2:
item[name] = key
results.append(item)
pass
pass
return results
group.to_list = to_list
'''
join joins two lists of dictionaries into a single list. similar to a sql join.
'''
def join(left_items,right_items, left, right, left_map=None, right_map=None):
results = []
def map(item):return item
if left_map == None: left_map = map
if right_map == None: right_map = map
grp = group(left_items, left)
for item in right_items:
keys = right(item)
if not isinstance(keys, list): keys = [keys]
current = grp
while len(keys)>0:
key = keys.pop(0)
if current != None and key in current:
current = current[key]
else: current = None
pass
if current != None:
right_item = right_map(item)
for item in current:
left_item = left_map(item)
record = {}
results.append(record)
for key in left_item:
record[key] = left_item[key]
for key in right_item:
record[key] = right_item[key]
pass
pass
pass
return results
def join_on_date(left_items, right_items):
if len(left_items) == 0 or len(right_items) == 0: return []
lfirst = left_items[0]
rfirst = right_items[0]
leftkey = 'date'
for key in lfirst:
if key.lower() == 'date': leftkey = key
pass
rightkey = 'date'
for key in rfirst:
if key.lower() == 'date': rightkey = key
pass
def left(item):
nonlocal leftkey
return item[leftkey]
def right(item):
nonlocal rightkey
return item[rightkey]
return join(left_items=left_items, right_items=right_items, left=left, right=right)
'''
sample script
'''
if __name__ == "__main__":
items = [{"name1":'scott', "name2":'jones', "age":12},{"name1":'scott', "name2":'jones', "age":12},{"name1":'scott', "name2":'jones', "age":12},
{"name1":'scott2', "name2":'jones', "age":22},{"name1":'scott3', "name2":'jones', "age":24},{"name1":'scott4', "name2":'jones', "age":30},
{"name1":'scott', "name2":'jones', "age":30},{"name1":'scott', "name2":'smith', "age":30},{"name1":'scott', "name2":'smith', "age":40}]
grp = group(items, lambda x:x['name1'], count_aggregator)
grp2 = group(items, lambda x:[x['name1'],x['name2']])
nlist = group.to_list(['name1','count'],grp)
join2 = join(items,items, lambda x:x['name1'], lambda x:x['name1'])
pass