Search code examples
pythoncountmultiple-columnsnested-loops

From matrix as lists of lists: count number of elements from a set x in each column. (python3)


I have a list of 256 functions as dicts, each with 4 pairs as in:

[{'a':'b', 'b':'c', 'c':'c', 'd':'a'}, ... ]

and would like to do the following...

  1. Apply function to each element in the domain from 1 to four times. For example for element 1 in the domain, 'a':

[f[a], f[f[a]], ..., f[f[f[f[a]]]] ]

This produces the following for the example dict/function in 1.

['b','c','c','c'] #for element a 
['c','c','c','c'] #for element b 
... etc.          #for element c
                  #for element d 
  1. view the matrix/list of lists as columns.

    4.Then, I wish to count the number of elements 'a' in col1, 2, 3 and 4. and do this for each domain element. I am hoping to produce something of the form:

[ [num a's in col 1, num of as in col 2, ...], [num b's in col 1, num of b's in col 2, ...], etc ]

for every single of the 256 function/dict elements. the final output should be something like:

[ [[0,1,1,0], 
   [2,1,1,0], 
   [0,0,0,0], 
   [2,2,2,4]], .... 256 of these] 

Here is the current code and the current output:

domain = ['a','b','c','d']
allf = [{'a':'a','b':'c','c':'d', 'd':'d'}, {'a':'b', 'b':'c', 'c':'d', 'd':'a'}]


def dictfunky():
    global dictfuncts
    dictfuncts = []
    for item in allf:
        di = dict(item)
        dictfuncts.append(di)
    print(dictfuncts)


def functmatnoz():
    global matlist
    matlist = []
    global elems
    for f in dictfuncts:
        elems = []
        for element in domain:
            forward = [f[element], f[f[element]], f[f[f[element]]], f[f[f[f[element]]]]]
            forward.reverse()
            back = forward
            elems.append(back)
        matlist.append(elems)
    print(matlist)



def sigma():
    global sigmamat
    sigmamat = []
    for element in domain:
        sig = []
        for column in matlist:
            size = column.count(element)
            sig.append(size)
        sigmamat.append(sig)
    print(sigmamat)

dictfunky()
functmatnoz()
sigma()

the first bit of output from the above is as follows, the main problem is of course the resultant string of 0's instead of my desired list of lists counting occurrences:

Out:

 >>> dictfunky()
[{'b': 'c', 'd': 'd', 'c': 'd', 'a': 'a'}, {'b': 'c', 'd': 'a', 'c': 'd', 'a': 'b'}]

>>> functmatnoz()
[[['a', 'a', 'a', 'a'], ['d', 'd', 'd', 'c'], ['d', 'd', 'd', 'd'], ['d', 'd', 'd', 'd']], [['a', 'd', 'c', 'b'], ['b', 'a', 'd', 'c'], ['c', 'b', 'a', 'd'], ['d', 'c', 'b', 'a']]]

>>> sigma()
[[0, 0], [0, 0], [0, 0], [0, 0]]
>>> 

desired out:

sigma()

[
  [[4,0,0,0], # num of a's in each col for funct 1
   [0,0,0,0], # num of b's in each col for funct 1 
   [0,1,0,0], # num of c's in .... 
   [0,3,4,4]] , 

  [[1,1,1,1], # num of a's in each col for funct 2 
   [1,1,1,1], # num of b's in each col for funct 2 
   [1,1,1,1], # etc. 
   [1,1,1,1]]
]

Solution

  • This seems to do what you want. I also got rid of the global variable references in the functions and made them just return a result (global variables are bad). The only significant logic change was to the sigma() function.

    domain = ['a','b','c','d']
    allf = [{'a':'a','b':'c','c':'d', 'd':'d'}, {'a':'b', 'b':'c', 'c':'d', 'd':'a'}]
    
    def dictfunky():
        dictfuncts = []
        for item in allf:
            di = dict(item)
            dictfuncts.append(di)
        return dictfuncts
    
    def functmatnoz():
        matlist = []
        for f in dictfuncts:
            elems = []
            for element in domain:
                forward = [f[element], f[f[element]], f[f[f[element]]], f[f[f[f[element]]]]]
                forward.reverse()
                back = forward
                elems.append(back)
            matlist.append(elems)
        return matlist
    
    def sigma():
        sigmamat = []
        for mat in matlist:
            col = []
            for element in domain:
                num_elem = []
                for results in mat:
                    count = results.count(element)
                    num_elem.append(count)
                col.append(num_elem)
            sigmamat.append(col)
        return sigmamat
    
    dictfuncts = dictfunky()
    matlist = functmatnoz()
    sigmamat = sigma()
    
    print('dictfuncts: {}'.format(dictfuncts))
    print('   matlist: {}'.format(matlist))
    print('  sigmamat: {}'.format(sigmamat))
    

    Output (line-breaks added for readability):

    dictfuncts: [{'c': 'd', 'b': 'c', 'a': 'a', 'd': 'd'},
                 {'c': 'd', 'b': 'c', 'a': 'b', 'd': 'a'}]
       matlist: [[['a', 'a', 'a', 'a'], ['d', 'd', 'd', 'c'], 
                  ['d', 'd', 'd', 'd'], ['d', 'd', 'd', 'd']],
                 [['a', 'd', 'c', 'b'], ['b', 'a', 'd', 'c'], 
                  ['c', 'b', 'a', 'd'], ['d', 'c', 'b', 'a']]]
      sigmamat: [[[4, 0, 0, 0],
                  [0, 0, 0, 0],
                  [0, 1, 0, 0],
                  [0, 3, 4, 4]],
                 [[1, 1, 1, 1],
                  [1, 1, 1, 1],
                  [1, 1, 1, 1],
                  [1, 1, 1, 1]]]
    

    Update

    The following optimized version, which uses nested list comprehensions, produces exactly the same results with a lot less code, and so might also be of interest to you. It also eliminates the remaining references to global variables in each of the functions by passing the those needed as additional arguments to them.

    domain = ['a','b','c','d']
    allf = [{'a':'a','b':'c','c':'d', 'd':'d'}, {'a':'b', 'b':'c', 'c':'d', 'd':'a'}]
    
    def dictfunky(allf):
        return [dict(item) for item in allf]
    
    def functmatnoz(dictfuncts, domain):
        return [[[f[f[f[f[element]]]],
                     f[f[f[element]]],
                        f[f[element]],
                           f[element]] for element in domain]
                                            for f in dictfuncts]
    
    def sigma(matlist, domain):
        return [[[[results.count(element) for results in mat]
                                            for element in domain]]
                                                for mat in matlist]
    
    dictfuncts = dictfunky(allf)
    matlist = functmatnoz(dictfuncts, domain)
    sigmamat = sigma(matlist, domain)
    
    print('dictfuncts: {}'.format(dictfuncts))
    print('   matlist: {}'.format(matlist))
    print('  sigmamat: {}'.format(sigmamat))