I know you can create easily nested lists in python like this:
[[1,2],[3,4]]
But how to create a 3x3x3 matrix of zeroes?
[[[0] * 3 for i in range(0, 3)] for j in range (0,3)]
or
[[[0]*3]*3]*3
Doesn't seem right. There is no way to create it just passing a list of dimensions to a method? Ex:
CreateArray([3,3,3])
In case a matrix is actually what you are looking for, consider the numpy package.
http://docs.scipy.org/doc/numpy/reference/generated/numpy.zeros.html#numpy.zeros
This will give you a 3x3x3 array of zeros:
numpy.zeros((3,3,3))
You also benefit from the convenience features of a module built for scientific computing.
List comprehensions are just syntactic sugar for adding expressiveness to list initialization; in your case, I would not use them at all, and go for a simple nested loop.
On a completely different level: do you think the n-dimensional array of NumPy could be a better approach?
Although you can use lists to implement multi-dimensional matrices, I think they are not the best tool for that goal.
NumPy addresses this problem
Link
>>> a = array( [2,3,4] )
>>> a
array([2, 3, 4])
>>> type(a)
<type 'numpy.ndarray'>
But if you want to use the Python native lists as a matrix the following helper methods can become handy:
import copy
def Create(dimensions, item):
for dimension in dimensions:
item = map(copy.copy, [item] * dimension)
return item
def Get(matrix, position):
for index in position:
matrix = matrix[index]
return matrix
def Set(matrix, position, value):
for index in position[:-1]:
matrix = matrix[index]
matrix[position[-1]] = value
Or use the nest function defined here, combined with repeat(0) from the itertools module:
nest(itertools.repeat(0),[3,3,3])
Just nest the multiplication syntax:
[[[0] * 3] * 3] * 3
It's therefore simple to express this operation using folds
def zeros(dimensions):
return reduce(lambda x, d: [x] * d, [0] + dimensions)
Or if you want to avoid reference replication, so altering one item won't affect any other you should instead use copies:
import copy
def zeros(dimensions):
item = 0
for dimension in dimensions:
item = map(copy.copy, [item] * dimension)
return item
Related
I need to make a matrix of objects in python. I have found other solutions in various languages however cannot find a reliable and efficient method to do this in python.
Given the class
class Cell():
def __init__(self):
self.value = none
self.attribute1 = False
self.attribute2 = False
I want to make a matrix of multiple 'cells' as efficiently as possible. Since the size of the matrix will be larger than 20 by 20, an iterative method would be useful. Any contributions are helpful
If you already have defined your objects, list comprehensions can help here:
num_rows = 5
num_cols = 6
row = [Cell() for i in range(num_cols)]
# The original way doesn't behave exactly right, this avoids
# deep nesting of the array. Also adding list(row) to create
# a new object rather than carrying references to row to all rows
mat = [list(row) for i in range(num_rows)]
#[[Cell(), Cell(), Cell()...], [...], ..., [Cell(), ..., Cell()]]
You can wrap them in numpy.array if you want to as well
NumPy array full
You could also use the numPy full method which is built-in and generates an n by m numpy array filled with your values:
mat = numpy.full((num_rows, num_cols), Cell())
The documentation can be found here
If you know in advance what size your matrix is you could initialize a numpy array using np.empty or np.zeros and then fill in the cells using indexing.
Or you could append items to lists and then convert to an array by np.array(list).
You'll want your matrix as a numpy array for any calculations you do.
Maybe just using nested lists?
Something like:
mtx = [[0, 1, 2], [3, 4, 5]]
mtx[1][1] # 4
Edit:
You can add elements to a list using the append method.
the_list = []
for item in iterator_or_something:
the_list.append(Cell(item.a, item,b))
If it is a fixed size and you know it:
the_list = []
for x in range(0, 500):
the_list.append(Cell())
Size = 20
Matrix = np.zeros((Size, Size))
for x in range(0, Size):
for y in range(0, Size):
Matrix[x][y] = Cell()
I'm trying to implement matrix class for simple operations with plain python (no numpy and etc.).
Here is part of it:
class Matrix(list):
def __getitem__(self, item):
try:
return list.__getitem__(self, item)
except TypeError:
rows, cols = item
return [row[cols] for row in self[rows]]
It allows to do things like this:
m = Matrix([[i+j for j in [0,1,2,3]] for i in [0,4,8,12]])
print(m[0:2, 0:2])
will print: [[0, 1], [4, 5]]
I also want to be able to add/multiply all submatrix elements by given value, like:
m[0:2, 0:2] += 1
print(m[0:2, 0:2])
should print: [[1, 2], [5, 6]]
It's not clear which magic methods should I implement to make it work?
First, inheriting from list is a bad move here. A matrix doesn't support the kinds of operations a list does; for example, you can't append to or extend a matrix, and item assignment is completely different. Your matrix should contain a list, not be a list.
As for what magic methods you need, m[0:2, 0:2] += 1 roughly translates to the following:
temp = m.__getitem__((slice(0, 2), slice(0, 2)))
temp = operator.iadd(temp, 1)
m.__setitem__((slice(0, 2), slice(0, 2)), temp)
where operator.iadd tries temp.__iadd__, temp.__add__, and (1).__radd__ to perform the addition.
You need to implement __getitem__ and __setitem__ to retrieve the submatrix and assign the new submatrix. Additionally, __getitem__ will need to return a matrix, rather than a list.
You should probably implement both __add__ and __iadd__; while __add__ alone would be sufficient for this case, __iadd__ will be necessary for operations like m += 1 to work in-place instead of replacing m with a new matrix object.
NO. __iadd__ will do the trick for you if the magic was:
m += 2
But the magic is executed over m[0:2, 0:2]. You need to ensure that when slicing your matrix you get a different object, and not a list of lists, since list of lists do not support __iadd__.
To find the maximal value in a matrix of numbers, we can code 5 lines to solve the problem:
ans = matrix[0][0]
for x in range(len(matrix)):
for y in range(len(matrix[0])):
ans = max(ans, matrix[x][y])
return ans
Is there a one line solution for this problem?
The one that I came up with is pretty awkward actually:
return max(max(matrix, key=max))
or
return max(map(max, matrix))
You can use generator expression to find the maximum in your matrix. That way you can avoid building the full list of matrix elements in memory.
maximum = max(max(row) for row in matrix)
instead of list comprehension as given in a previous answer here
maximum = max([max(row) for row in matrix])
This is from PEP (the rationale section):
...many of the use cases do not need to have a full list created in
memory. Instead, they only need to iterate over the elements one at a
time.
...
Generator expressions are especially useful with functions like sum(), min(), and max() that reduce an iterable input to a single value
...
The utility of generator expressions is greatly enhanced when combined with reduction functions like sum(), min(), and max().
Also, take a look at this SO post: Generator Expressions vs. List Comprehension.
By matrix, I assume you mean a 2d-list.
max([max(i) for i in matrix])
using numpy.amax:
import numpy as np
>>> my_array
array([[1, 2, 3],
[9, 8, 6]])
>>> np.amax(my_array)
9
You can also flatten your array:
from itertools import chain
flatten = chain.from_iterable
max(flatten(matrix))
I am trying to use itertools.product to manage the bookkeeping of some nested for loops, where the number of nested loops is not known in advance. Below is a specific example where I have chosen two nested for loops; the choice of two is only for clarity, what I need is a solution that works for an arbitrary number of loops.
This question provides an extension/generalization of the question appearing here:
Efficient algorithm for evaluating a 1-d array of functions on a same-length 1d numpy array
Now I am extending the above technique using an itertools trick I learned here:
Iterating over an unknown number of nested loops in python
Preamble:
from itertools import product
def trivial_functional(i, j): return lambda x : (i+j)*x
idx1 = [1, 2, 3, 4]
idx2 = [5, 6, 7]
joint = [idx1, idx2]
func_table = []
for items in product(*joint):
f = trivial_functional(*items)
func_table.append(f)
At the end of the above itertools loop, I have a 12-element, 1-d array of functions, func_table, each element having been built from the trivial_functional.
Question:
Suppose I am given a pair of integers, (i_1, i_2), where these integers are to be interpreted as the indices of idx1 and idx2, respectively. How can I use itertools.product to determine the correct corresponding element of the func_table array?
I know how to hack the answer by writing my own function that mimics the itertools.product bookkeeping, but surely there is a built-in feature of itertools.product that is intended for exactly this purpose?
I don't know of a way of calculating the flat index other than doing it yourself. Fortunately this isn't that difficult:
def product_flat_index(factors, indices):
if len(factors) == 1: return indices[0]
else: return indices[0] * len(factors[0]) + product_flat_index(factors[1:], indices[1:])
>> product_flat_index(joint, (2, 1))
9
An alternative approach is to store the results in a nested array in the first place, making translation unnecessary, though this is more complex:
from functools import reduce
from operator import getitem, setitem, itemgetter
def get_items(container, indices):
return reduce(getitem, indices, container)
def set_items(container, indices, value):
c = reduce(getitem, indices[:-1], container)
setitem(c, indices[-1], value)
def initialize_table(lengths):
if len(lengths) == 1: return [0] * lengths[0]
subtable = initialize_table(lengths[1:])
return [subtable[:] for _ in range(lengths[0])]
func_table = initialize_table(list(map(len, joint)))
for items in product(*map(enumerate, joint)):
f = trivial_functional(*map(itemgetter(1), items))
set_items(func_table, list(map(itemgetter(0), items)), f)
>>> get_items(func_table, (2, 1)) # same as func_table[2][1]
<function>
So numerous answers were quite useful, thanks to everyone for the solutions.
It turns out that if I recast the problem slightly with Numpy, I can accomplish the same bookkeeping, and solve the problem I was trying to solve with vastly improved speed relative to pure python solutions. The trick is just to use Numpy's reshape method together with the normal multi-dimensional array indexing syntax.
Here's how this works. We just convert func_table into a Numpy array, and reshape it:
func_table = np.array(func_table)
component_dimensions = [len(idx1), len(idx2)]
func_table = np.array(func_table).reshape(component_dimensions)
Now func_table can be used to return the correct function not just for a single 2d point, but for a full array of 2d points:
dim1_pts = [3,1,2,1,3,3,1,3,0]
dim2_pts = [0,1,2,1,2,0,1,2,1]
func_array = func_table[dim1_pts, dim2_pts]
As usual, Numpy to the rescue!
This is a little messy, but here you go:
from itertools import product
def trivial_functional(i, j): return lambda x : (i+j)*x
idx1 = [1, 2, 3, 4]
idx2 = [5, 6, 7]
joint = [enumerate(idx1), enumerate(idx2)]
func_map = {}
for indexes, items in map(lambda x: zip(*x), product(*joint)):
f = trivial_functional(*items)
func_map[indexes] = f
print(func_map[(2, 0)](5)) # 40 = (3+5)*5
I'd suggest using enumerate() in the right place:
from itertools import product
def trivial_functional(i, j): return lambda x : (i+j)*x
idx1 = [1, 2, 3, 4]
idx2 = [5, 6, 7]
joint = [idx1, idx2]
func_table = []
for items in product(*joint):
f = trivial_functional(*items)
func_table.append(f)
From what I understood from your comments and your code, func_table is simply indexed by the occurence of a certain input in the sequence. You can access it back again using:
for index, items in enumerate(product(*joint)):
# because of the append(), index is now the
# position of the function created from the
# respective tuple in join()
func_table[index](some_value)
This question already has answers here:
Why does this iterative list-growing code give IndexError: list assignment index out of range? How can I repeatedly add (append) elements to a list?
(9 answers)
Closed 4 months ago.
This is such a simple issue that I don't know what I'm doing wrong. Basically I want to iterate through the items in an empty list and increase each one according to some criteria. This is an example of what I'm trying to do:
list1 = []
for i in range(5):
list1[i] = list1[i] + 2*i
This fails with an list index out of range error and I'm stuck. The expected result (what I'm aiming at) would be a list with values:
[0, 2, 4, 6, 8]
Just to be more clear: I'm not after producing that particular list. The question is about how can I modify items of an empty list in a recursive way. As gnibbler showed below, initializing the list was the answer. Cheers.
Ruby (for example) lets you assign items beyond the end of the list. Python doesn't - you would have to initialise list1 like this
list1 = [0] * 5
So when doing this you are actually using i so you can just do your math to i and just set it to do that. there is no need to try and do the math to what is going to be in the list when you already have i. So just do list comprehension:
list1 = [2*i for i in range(5)]
Since you say that it is more complex, just don't use list comprehension, edit your for loop as such:
for i in range(5):
x = 2*i
list1[i] = x
This way you can keep doing things until you finally have the outcome you want, store it in a variable, and set it accordingly! You could also do list1.append(x), which I actually prefer because it will work with any list even if it's not in order like a list made with range
Edit: Since you want to be able to manipulate the array like you do, I would suggest using numpy! There is this great thing called vectorize so you can actually apply a function to a 1D array:
import numpy as np
list1 = range(5)
def my_func(x):
y = x * 2
vfunc = np.vectorize(my_func)
vfunc(list1)
>>> array([0, 2, 4, 6, 8])
I would advise only using this for more complex functions, because you can use numpy broadcasting for easy things like multiplying by two.
Your list is empty, so when you try to read an element of the list (right hand side of this line)
list1[i] = list1[i] + 2*i
it doesn't exist, so you get the error message.
You may also wish to consider using numpy. The multiplication operation is overloaded to be performed on each element of the array. Depending on the size of your list and the operations you plan to perform on it, using numpy very well may be the most efficient approach.
Example:
>>> import numpy
>>> 2 * numpy.arange(5)
array([0, 2, 4, 6, 8])
I would instead write
for i in range(5):
list1.append(2*i)
Yet another way to do this is to use the append method on your list. The reason you're getting an out of range error is because you're saying:
list1 = []
list1.__getitem__(0)
and then manipulate this item, BUT that item does not exist since your made an empty list.
Proof of concept:
list1 = []
list1[1]
IndexError: list index out of range
We can, however, append new stuff to this list like so:
list1 = []
for i in range(5):
list1.append(i * 2)