Mostly Linux & Python syntax notes and hyperlinks.

Friday, March 28, 2014

python: 1-d dictionary for counting heirarchical attributes

This dictionary method uses concatenated characters instead of sub-dictionaries to track the hierarchical counts. e.g Number of Dogs could be pets['D'], Number of red dogs could be pets['DR']. Number of red dogs living in Cambridge could be pets['DRC'].

What follows is the general dictionary-building method, followed by a method written to illustrate how it could be used, followed by the printout from the test method.
# Given a list of lists, build a set of keys that combine fields from each list
# return a 1-d dictionary of these keys initialized to input_default
#
# @param list_of_lists = list of key-lists - Should be single unique characters.
# @param input_default [optional] Value to initialize each dictionary entry
# if input_default parameter not given, then 0 is used
def build1Dictionary(list_of_lists,input_default=0):
    number_of_lists=len(list_of_lists)
    if number_of_lists==0:
        return dict()
    keylist=list_of_lists[0]
    if number_of_lists==1:
        return dict.fromkeys(keylist,input_default)
    for next_list in list_of_lists[1:]:
        new_list=list(keylist)
        for key in keylist:
            for xkey in next_list:
                new_list.append(key+xkey)
        keylist=new_list
    return dict.fromkeys(keylist,input_default)

# Here is a method to test the dictionary:
def count_pets():
    #Create the dictionary
    pets=['D','C','F','B']
    gender=['g','b']
    home=['R','S','U']
    words=dict(D="Dog",C="Cat",F="Fish",B="Bird",\
       g="Girl",b="Boy",R="Rural",S="Suburban",U="City")
    pets_dict=build1Dictionary([pets,gender,home])
   
    #fill the dictionary with some counts
    data=["DgS","DgS","DbR","CgU","FgS","CgR","BbR"]
    for pet in data:
        p=pet[0:1]
        g=pet[1:2]
        h=pet[2:3]
        pets_dict[p]+=1
        pets_dict[p+g]+=1
        pets_dict[p+g+h]+=1
   
    #Print the counts indented by level of heiarchy
    for p in pets:
        print ("%d %s(s)" % (pets_dict[p],words[p]))
        for g in gender:
            if pets_dict[p+g]>0:
                print ("  %d owned by a %s" % \
                   (pets_dict[p+g],words[g]))
                for h in home:
                    if pets_dict[p+g+h] > 0:
                        print("    %d in %s environment." % \
                            (pets_dict[p+g+h],words[h]))
   

if __name__ == '__main__':
    count_pets()
Then when I run it, it prints out:
3 Dog(s)
  2 owned by a Girl
    2 in Suburban environment.
  1 owned by a Boy
    1 in Rural environment.
2 Cat(s)
  2 owned by a Girl
    1 in Rural environment.
    1 in City environment.
1 Fish(s)
  1 owned by a Girl
    1 in Suburban environment.
1 Bird(s)
  1 owned by a Boy
    1 in Rural environment.

Tuesday, March 11, 2014

Python: build and initialize a dictionary from a list of lists

OK, so building on the last post. Here's a general purpose function that takes a list of desired key-lists, and returns a multi-dimensional data dictionary.
##
## Takes dictionary and a list of desired keys
## adds the keys to the dictionary, initializing them to input parameter
#
# @param input_dictionary Name of input dictionary
# @param input_keys List of desired keys
# @param input_default [optional] Value to initialize each dictionary entry
# if input_default parameter not given, then 0 is used
#
#
def setDictionaryDefaults(input_dictionary,input_keys,input_default=0):
    for key in input_keys:
      input_dictionary.setdefault(key,input_default)


##
# Given a list of lists, build a multidimensional dictionary, initialized to optional input parameter
#
# @param list_of_lists = list of key-lists
# @param input_default [optional] Value to initialize each dictionary entry
# if input_default parameter not given, then 0 is used
def buildDictionary(list_of_lists,input_default=0):
    d=dict()
    number_of_lists=len(list_of_lists)
    if number_of_lists==0:
        return d
    setDictionaryDefaults(d,list_of_lists[0],input_default)
    if number_of_lists==1:
        return d
    next_d=dict()
    for next_list in list_of_lists[1:]:
        setDictionaryDefaults(next_d,next_list,d)
        d=next_d
        next_d=dict()
    return d
Here I test it:
 Python 2.4.1 (#2, Jul 24 2007, 12:14:31)
[GCC 3.2.3 20030502 (Red Hat Linux 3.2.3-34)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from lists_to_dict import buildDictionary
>>> a=['a','b']
>>> c=[a]
>>> d=buildDictionary(c,1)
>>> d
{'a': 1, 'b': 1}
>>> q=['R','S','T']
>>> x=['X','XX','XXX']
>>> y=['Y','YY']
>>> c=[a,q,x,y]
>>> c
[['a', 'b'], ['R', 'S', 'T'], ['X', 'XX', 'XXX'], ['Y', 'YY']]
>>> d=buildDictionary(c,1)
>>> d
{'Y': {'X': {'S': {'a': 1, 'b': 1}, 'R': {'a': 1, 'b': 1}, 'T': {'a': 1, 'b': 1}}, 'XX': {'S': {'a': 1, 'b': 1}, 'R': {'a': 1, 'b': 1}, 'T': {'a': 1, 'b': 1}}, 'XXX': {'S': {'a': 1, 'b': 1}, 'R': {'a': 1, 'b': 1}, 'T': {'a': 1, 'b': 1}}}, 'YY': {'X': {'S': {'a': 1, 'b': 1}, 'R': {'a': 1, 'b': 1}, 'T': {'a': 1, 'b': 1}}, 'XX': {'S': {'a': 1, 'b': 1}, 'R': {'a': 1, 'b': 1}, 'T': {'a': 1, 'b': 1}}, 'XXX': {'S': {'a': 1, 'b': 1}, 'R': {'a': 1, 'b': 1}, 'T': {'a': 1, 'b': 1}}}}
>>>
>>> c=[]
>>> d=buildDictionary(c,1)
>>> d
{}
>>> a=['q','r']
>>> c=[a]
>>> buildDictionary(c)
{'q': 0, 'r': 0}
>>> d=buildDictionary(c)
>>> d
{'q': 0, 'r': 0}
>>>

python: building 3-D dictionary

We're using 2.4 so don't have defaultdict. Her's a way to create one using dict() and setdefault():

>>> hid=dict()
>>> hid.setdefault('H',0)
0
>>> hid.setdefault('I',0)
0
>>> bkd=dict()
>>> bkd
{}
>>> bkd.setdefault('Z',hid)
{'I': 0, 'H': 0}
>>> bkd
{'Z': {'I': 0, 'H': 0}}
>>> bkd.setdefault('CH',hid)
{'I': 0, 'H': 0}
>>> bkd
{'CH': {'I': 0, 'H': 0}, 'Z': {'I': 0, 'H': 0}}
>>> epd=dict()
>>> epd.setdefault('E',bkd)
{'CH': {'I': 0, 'H': 0}, 'Z': {'I': 0, 'H': 0}}
>>> epd.setdefault('P',bkd)
{'CH': {'I': 0, 'H': 0}, 'Z': {'I': 0, 'H': 0}}
>>> epd
{'P': {'CH': {'I': 0, 'H': 0}, 'Z': {'I': 0, 'H': 0}}, 'E': {'CH': {'I': 0, 'H': 0}, 'Z': {'I': 0, 'H': 0}}}
Now use it:
>>> ep=['E','P']
>>> bk=['Z','CH']
>>> hi=['H','I']
>>> i=0
>>> for e in ep:
...   for b in bk:
...     for h in hi:
...       epd[e][b][h]=i
...       i+=1
...
>>> epd
{'P': {'CH': {'I': 7, 'H': 6}, 'Z': {'I': 7, 'H': 6}}, 'E': {'CH': {'I': 7, 'H': 6}, 'Z': {'I': 7, 'H': 6}}}
>>> epd['E']['Z']['H']
6
I want to start with lists and build dictionaries from there. Here's the start of that automation:
>>> def setDefaults(k,d):
...   for key in k:
...     d.setdefault(key,0)
...
>>> kay=['A','B','C','D']
>>> dee=dict()
>>> setDefaults(kay,dee)
>>> dee
{'A': 0, 'C': 0, 'B': 0, 'D': 0}
Now update setDefaults to take the default initializer as a parameter:
>>> def setDefaults(k,d,i):
...   for key in k:
...     d.setdefault(key,i)
...
>>> kay
['A', 'B', 'C', 'D']
>>> d2=dict()
>>> setDefaults(kay,d2,2)
>>> d2
{'A': 2, 'C': 2, 'B': 2, 'D': 2}
OK, now here we start with three lists and build a 3-d dictionary using the setDefaults() method:
>>> kay
['A', 'B', 'C', 'D']
>>> ell=['X','Y','Z']
>>> grk=['pi','ro','lamtha','tau']
>>> kay_ell=dict()
>>> kay_d=dict()
>>> setDefaults(kay,kay_d,0)
>>> kay_d
{'A': 0, 'C': 0, 'B': 0, 'D': 0}
>>> setDefaults(ell,kay_ell,kay_d)
>>> ell
['X', 'Y', 'Z']
>>> kay_ell
{'Y': {'A': 0, 'C': 0, 'B': 0, 'D': 0}, 'X': {'A': 0, 'C': 0, 'B': 0, 'D': 0}, 'Z': {'A': 0, 'C': 0, 'B': 0, 'D': 0}}
>>> kay_ell_grk=dict()
>>> setDefaults(grk,kay_ell_grk,kay_ell)
>>> kay_ell_grk
{'tau': {'Y': {'A': 0, 'C': 0, 'B': 0, 'D': 0}, 'X': {'A': 0, 'C': 0, 'B': 0, 'D': 0}, 'Z': {'A': 0, 'C': 0, 'B': 0, 'D': 0}}, 'pi': {'Y': {'A': 0, 'C': 0, 'B': 0, 'D': 0}, 'X': {'A': 0, 'C': 0, 'B': 0, 'D': 0}, 'Z': {'A': 0, 'C': 0, 'B': 0, 'D': 0}}, 'ro': {'Y': {'A': 0, 'C': 0, 'B': 0, 'D': 0}, 'X': {'A': 0, 'C': 0, 'B': 0, 'D': 0}, 'Z': {'A': 0, 'C': 0, 'B': 0, 'D': 0}}, 'lamtha': {'Y': {'A': 0, 'C': 0, 'B': 0, 'D': 0}, 'X': {'A': 0, 'C': 0, 'B': 0, 'D': 0}, 'Z': {'A': 0, 'C': 0, 'B': 0, 'D': 0}}}
>>>