Mailing List Archive

class Pivot
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@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