Would it be considered "pythonic" to use a nested defaultdict where bottom level is defaulted to 0 for counting?
I am building something to sort and add values from an API response. I ended up going with an interesting structure, and I just want to make sure there's nothing inherently wrong with it.
from collections import defaultdict # Helps create a unique nested default dict object # for code readability def dict_counter(): return defaultdict(lambda: 0) # Creates the nested defaultdict object ad_data = defaultdict(dict_counter) # Sorts each instance into its channel, and # adds the dict values incrimentally for ad in example: # Collects channel and metrics channel = ad['ad_group']['type_'] metrics = dict( impressions= int(ad['metrics']['impressions']), clicks = int(ad['metrics']['clicks']), cost = int(ad['metrics']['cost_micros']) ) # Adds the variables ad_data[channel]['impressions'] += metrics['impressions'] ad_data[channel]['clicks'] += metrics['clicks'] ad_data[channel]['cost'] += metrics['cost']
The output is as desired. Again, I just want to make sure I'm not reinventing the wheel or doing something really inefficient here.
defaultdict(<function __main__.dict_counter()>, {'DISPLAY_STANDARD': defaultdict(<function __main__.dict_counter.<locals>.<lambda>()>, {'impressions': 14, 'clicks': 4, 'cost': 9}), 'SEARCH_STANDARD': defaultdict(<function __main__.dict_counter.<locals>.<lambda>()>, {'impressions': 6, 'clicks': 2, 'cost': 4})})
Here's what my input data would look like:
example = [ { 'campaign': { 'resource_name': 'customers/12345/campaigns/12345', 'status': 'ENABLED', 'name': 'test_campaign_2' }, 'ad_group': { 'resource_name': 'customers/12345/adGroups/12345', 'type_': 'DISPLAY_STANDARD'}, 'metrics': { 'clicks': '1', 'cost_micros': '3', 'impressions': '5' }, 'ad_group_ad': { 'resource_name': 'customers/12345/adGroupAds/12345~12345', 'ad': { 'resource_name': 'customers/12345/ads/12345' } } }, { 'campaign': { 'resource_name': 'customers/12345/campaigns/12345', 'status': 'ENABLED', 'name': 'test_campaign_2' }, 'ad_group': { 'resource_name': 'customers/12345/adGroups/12345', 'type_': 'SEARCH_STANDARD'}, 'metrics': { 'clicks': '2', 'cost_micros': '4', 'impressions': '6' }, 'ad_group_ad': { 'resource_name': 'customers/12345/adGroupAds/12345~12345', 'ad': { 'resource_name': 'customers/12345/ads/12345' } } }, { 'campaign': { 'resource_name': 'customers/12345/campaigns/12345', 'status': 'ENABLED', 'name': 'test_campaign_2' }, 'ad_group': { 'resource_name': 'customers/12345/adGroups/12345', 'type_': 'DISPLAY_STANDARD'}, 'metrics': { 'clicks': '3', 'cost_micros': '6', 'impressions': '9' }, 'ad_group_ad': { 'resource_name': 'customers/12345/adGroupAds/12345~12345', 'ad': { 'resource_name': 'customers/12345/ads/12345' } } } ]
Thanks!