0

I have some data like this:

FeatureName,Machine,LicenseHost
Feature1,host1,lichost1
Feature1,host2,lichost1
Feature2,host1,lichost2
Feature1,host1,lichost1

and so on...

I want to maintain a nested dictionary where the first level of key is the feature name, next is machine name, finally license host, and the value is the number of times that combination occurs.

Something like:

dictionary['Feature1']['host1']['lichost1'] = 2
dictionary['Feature1']['host2']['lichost1'] = 1
dictionary['Feature2']['host1']['lichost2'] = 1

The obvious way of creating/updating such a dictionary is (assuming I am reading the data line by line from the CSV):

for line in file:
    feature, machine, license = line.split(',')
    if feature not in dictionary:
        dictionary[feature] = {}
    if machine not in dictionary[feature]:
        dictionary[feature][machine] = {}
    if license not in dictionary[feature][machine]:
        dictionary[feature][machine][license] = 1
    else:
        dictionary[feature][machine][license] += 1

This ensures that I will never run into key not found errors at any level.

What is the best way to do the above (for any number of nested levels) ?

shikhanshu
  • 1,466
  • 2
  • 16
  • 32
  • 2
    You are looking for [nested defaultdict](http://stackoverflow.com/a/19189356/1558430) – Brian Jan 05 '16 at 22:05

1 Answers1

2

You could use defaultdict:

from collections import defaultdict
import csv

def d1(): return defaultdict(int)
def d2(): return defaultdict(d1)
def d3(): return defaultdict(d2)
dictionary = d3()

with open('input.csv') as input_file:
    next (input_file);
    for line in csv.reader(input_file):
        dictionary[line[0]][line[1]][line[2]] += 1

assert dictionary['Feature1']['host1']['lichost1'] == 2
assert dictionary['Feature1']['host2']['lichost1'] == 1
assert dictionary['Feature2']['host1']['lichost2'] == 1
assert dictionary['InvalidFeature']['host1']['lichost1'] == 0

If the multiple function defs bother you, you can say the same thing more succinctly:

dictionary = defaultdict(lambda: defaultdict(lambda: defaultdict(int)))
Robᵩ
  • 163,533
  • 20
  • 239
  • 308