Two functions useful when you don't use a numerical library. The first one creates a tensor, hopefully in the correct way, avoiding the mutability trap. The second one transposes a 2D matrix keeping the type of the lists/tuples used.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | from types import NoneType # for tensor
from copy import deepcopy # for tensor
def tensor(sizes=0, elem=0):
"""tensor(sizes=0, elem=0): creates a list of lists of lists...
The parameter sizes can be a number or a tuple/list or sizes.
>>> tensor()
[]
>>> tensor(())
[]
It works with a single number or a sequence of numbers:
>>> tensor(3)
[0, 0, 0]
>>> tensor((3))
[0, 0, 0]
>>> tensor((3), None)
[None, None, None]
>>> tensor((2, 3)) # array of 2 rows and 3 colums.
[[0, 0, 0], [0, 0, 0]]
>>> tensor((2, 3), 2)
[[2, 2, 2], [2, 2, 2]]
>>> tensor((1, 2, 3))
[[[0, 0, 0], [0, 0, 0]]]
>>> tensor((2, 2, 3))
[[[0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]]
It works with mutables too, calling deepcopy:
>>> r = tensor((2, 3), [3])
>>> r
[[[3], [3], [3]], [[3], [3], [3]]]
>>> r[0][2][0] = 0
>>> r
[[[3], [3], [0]], [[3], [3], [3]]]
"""
if isinstance(sizes, (int, long)):
sizes = [sizes]
elif not isinstance(sizes, list):
sizes = list(sizes)
result = []
if sizes:
first = sizes.pop()
if isinstance(elem, (int, long, basestring, tuple, NoneType, bool)):
result = [elem] * first
else:
result = [deepcopy(elem) for i in xrange(first)]
while sizes:
result = [deepcopy(result) for i in xrange(sizes.pop())]
return result
def transpose(m):
"""transpose(m): transposes a 2D matrix, made of tuples or lists of tuples or lists,
keeping their type.
>>> transpose([])
Traceback (most recent call last):
...
IndexError: list index out of range
>>> transpose([[]])
[]
>>> transpose([1,2,3])
Traceback (most recent call last):
...
TypeError: zip argument #1 must support iteration
>>> transpose([[1,2,3]])
[[1], [2], [3]]
>>> transpose( [[2, 2, 2], [2, 2, 2]] )
[[2, 2], [2, 2], [2, 2]]
>>> transpose( [(2, 2, 2), (2, 2, 2)] )
[(2, 2), (2, 2), (2, 2)]
>>> transpose( ([2, 2, 2], [2, 2, 2]) )
([2, 2], [2, 2], [2, 2])
>>> transpose( ((2, 2, 2), (2, 2, 2)) )
((2, 2), (2, 2), (2, 2))
>>> t = [[[1], [2]], [[3], [4]], [[5], [6]]]
>>> transpose(t)
[[[1], [3], [5]], [[2], [4], [6]]]
"""
if isinstance(m, list):
if isinstance(m[0], list):
return map(list, zip(*m))
else:
return zip(*m) # faster
else:
if isinstance(m[0], list):
return tuple(map(list, zip(*m)))
else:
return tuple( zip(*m) )
if __name__ == "__main__":
import doctest
doctest.testmod()
print "Tests done."
|
Tags: algorithms
Deepcopy. I really don't like deepcopying values using the deepcopy() function. It slows your algorithm down and is kind of a last resort. Although the simplicity of the algorithm may be destroyed I would suggest more case analysis. For instance if L is a list of immutables it is appropriate to clone it using K = L[:]. One might even think about using a lazy datatype, that creates columns on demand ( depends on usage of course ).