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
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