class Pivot

david.stegbauer at cz.opel.com david.stegbauer at cz.opel.com
Tue Aug 3 09:22:58 CEST 1999


Hello,

below is code of my Pivot class. It is inspired by Excel "Pivot Tables" or
database "cross tables". Pivot act as very simple matrix with generalized
indexes - index can be any type with defined ordering (i.e. __cmp__ function in
class) and hash value (i.e. __hash__ function in class).

Pivot only allow setting and getting items and incrementing values. Note, that
if Pivot doesn't contain data for given indexes, it automatically append
required row/column and initially set new values to 0 (zero).

I'm using this class daily about two months in conjunction with my PivotWriter
class (still need to be improved). So Pivot seems to be functional, but it isn't
perfect.

8<-----------------------------------------------------
import string

#rows are continuous blocks
#r0c0, r0c1, r0c2, r1c0, r1c1, r1c2, etc...
class Pivot:
    """Pivot: matrix with any type of index and value (numeric prefered)
       1999 David Stegbauer, david.stegbauer at cz.opel.com
       freeware"""
    def __init__(self):
        self.rows = {}  #map row labels to row numbers
        self.rowcnt = 0 #row count
        self.cols = {}  #map column labels to numbers
        self.colcnt = 0 #column count
        self.data = []  #continuous block of own data
    def __del__(self):
        pass
    #---
    def _indexof(self, col, row):
        """calculate index to self.data from row and colum labels
        if such row or column is not present, it is added"""
        if self.rowcnt == 0:     #colcnt has to be also zero...
            self.cols[col] = 0
            self.rows[row] = 0
            self.data.append(0)
            self.rowcnt = 1
            self.colcnt = 1
            return 0
        if not self.cols.has_key(col):  #then append new column
            self.cols[col] = self.colcnt
            for i in xrange(self.rowcnt*self.colcnt, self.colcnt-1,
-self.colcnt):
                self.data.insert(i, 0)
            self.colcnt = self.colcnt + 1
        if not self.rows.has_key(row):  #then append new row
            self.rows[row] = self.rowcnt
            self.data = self.data + (self.colcnt) * [0]
            self.rowcnt = self.rowcnt + 1
        return self.rows[row] * self.colcnt + self.cols[col]    #calc index

    def setitem(self, col, row, value):
        """directly set value in Pivot"""
        i = self._indexof(col, row)
        self.data[i] = value

    def getitem(self, col, row):
        """get value from Pivot"""
        i = self._indexof(col, row)
        return self.data[i]

    def increment(self, col, row, val=1):
        """increment value in Pivot, default by one"""
        i = self._indexof(col, row)
        self.data[i] = self.data[i] + val

    def rownames(self):
        """get sorted row labels"""
        rn = self.rows.keys()
        rn.sort()
        return rn

    def colnames(self):
        """get sorted colum labels"""
        cn = self.cols.keys()
        cn.sort()
        return cn

    def coltotals(self):
        """get column totals (sums), bad ordered"""
        tot = (self.colcnt) * [0]
        for j in xrange(len(self.data)):
            i = j % self.colcnt
            tot[i] = tot[i] + self.data[j]
        # TO DO:  sort same as colnames() is
        return tot

    def formatrow(self, row, fmt, sep):
        if not self.rows.has_key(row):
            return ""
        cn = self.cols.keys()
        cn.sort()                   #column indexes
        i = self.rows[row] * self.colcnt   #index base
        r = ""                      #return value
        if type(fmt) != type("") or fmt == "":
            do_fmt = 0
        else:
            do_fmt = 1          #should apply format
        for e in cn:
            if do_fmt:          #apply format
                r = r + fmt % self.data[i + self.cols[e]] + sep
            else:
                r = r + `self.data[i + self.cols[e]]` + sep  #backticks - repr
        return r

    def format(self, itemformat = '', rowsep = '\n', colsep = '\t'):
        cn = self.cols.keys(); cn.sort()
        r =  reduce(lambda x,y,s=colsep: x+str(y)+s, cn, colsep)  #column labels
        cn = map(lambda i, dic=self.cols: dic[i], cn)             #column
indexes
        rnames = self.rows.keys(); rnames.sort()                  #row labels
        rn = map(lambda i, dic=self.rows: dic[i], rnames)         #row indexes
        r = r + rowsep

        if type(itemformat) != type("") or itemformat == "":
            do_itemformat = 0
        else:
            do_itemformat = 1          #should apply format
        i = 0
        for row in rn:
            r = r + str(rnames[i]) + colsep; i = i + 1
            for col in cn:
                if do_itemformat:          #apply format
                    r = r + itemformat % self.data[row*self.colcnt + col] +
colsep
                else:
                    r = r + str(self.data[row*self.colcnt + col]) + colsep
            r = r + rowsep
        return r






More information about the Python-list mailing list