Python Iterating through nested list using list comprehension - python

I'm working on Euler Project, problem 11, which involves finding the greatest product of all possible combinations of four adjacent numbers in a grid. I've split the numbers into a nested list and used a list comprehension to slice the relevant numbers, like this:
if x+4 <= len(matrix[x]): #check right
my_slice = [int(matrix[x][n]) for n in range(y,y+4)]
...and so on for the other cardinal directions. So far, so good. But when I get to the diagonals things get problematic. I tried to use two ranges like this:
if x+4 <= len(matrix[x]) and y-4 >=0:# check up, right
my_slice = [int(matrix[m][n]) for m,n in ((range(x,x+4)),range(y,y+4))]
But this yields the following error:
<ipython-input-53-e7c3ebf29401> in <listcomp>(.0)
48 if x+4 <= len(matrix[x]) and y-4 >=0:# check up, right
---> 49 my_slice = [int(matrix[m][n]) for m,n in ((range(x,x+4)),range(y,y+4))]
ValueError: too many values to unpack (expected 2)
My desired indices for x,y values of [0,0] would be ['0,0','1,1','2,2','3,3']. This does not seem all that different for using the enumerate function to iterate over a list, but clearly I'm missing something.
P.S. My apologies for my terrible variable nomenclature, I'm a work in progress.

You do not need to use two ranges, simply use one and apply it twice:
my_slice = [int(matrix[m][m-x+y]) for m in range(x,x+4)]
Since your n is supposed to be attached to range(y,y+4) we know that there will always be a difference of y-x between m and n. So instead of using two variables, we can counter the difference ourselves.
Or in case you still wish to use two range(..) constructs, you can use zip(..) which takes a list of generators, consumes them concurrently and emits tuples:
my_slice = [int(matrix[m][n]) for m,n in zip(range(x,x+4),range(y,y+4))]
But I think this will not improve performance because of the tuple packing and unpacking overhead.

[int(matrix[x+d][n+d]) for d in range(4)] for one diagonal.
[int(matrix[x+d][n-d]) for d in range(4)] for the other.
Btw, better use standard matrix index names, i.e., row i and column j. Not x and y. It's confusing. I think you even confused yourself, as for example your if x+4 <= len(matrix[x]) tests x against the second dimension length but uses it in the first dimension. Huh?

Related

Is there a better way to send multiple arguments to itertools.product?

I am trying to create itertools.product from a 2D list containing many rows. For example, consider a list s:
[[0.7168573116730971,
1.3404415914042531,
1.8714268721791336,
11.553051251803975],
[0.6702207957021266,
1.2476179147860895,
1.7329576877705954,
10.635778602978927],
[0.6238089573930448,
1.1553051251803976,
1.5953667904468385,
9.725277699842893],
[0.5776525625901988,
1.0635778602978927,
1.4587916549764335,
8.822689900641748]]
I want to compute itertools.product between the 4 rows of the list:
pr = []
for j in (it.product(s[0],s[1],s[2],s[3])):
pr.append(j)
This gives the necessary result for pr which has dimensions 256,4 where 256 is (number of columns^number of rows). But, is there a better way to send all the rows of the list s as arguments without having to write each row's name. This would be annoying if it were to be done for a larger list.
I guess numpy.meshgrid can be used if s was a numpy.array. But even there, I'll have to jot down each row one by one as arguments.
You can use the unpacking notation * in Python for this:
import itertools as it
s = [[0.7168573116730971,
1.3404415914042531,
1.8714268721791336,
11.553051251803975],
[0.6702207957021266,
1.2476179147860895,
1.7329576877705954,
10.635778602978927],
[0.6238089573930448,
1.1553051251803976,
1.5953667904468385,
9.725277699842893],
[0.5776525625901988,
1.0635778602978927,
1.4587916549764335,
8.822689900641748]]
pr = []
for j in (it.product(*s):
pr.append(j)
It will send each item of your list s to the product function

Coding an iterated sum of sums in python

For alpha and k fixed integers with i < k also fixed, I am trying to encode a sum of the form
where all the x and y variables are known beforehand. (this is essentially the alpha coordinate of a big iterated matrix-vector multiplication)
For a normal sum varying over one index I usually create a 1d array A and set A[i] equal to the i indexed entry of the sum then use sum(A), but in the above instance the entries of the innermost sum depend on the indices in the previous sum, which in turn depend on the indices in the sum before that, all the way back out to the first sum which prevents me using this tact in a straightforward manner.
I tried making a 2D array B of appropriate length and width and setting the 0 row to be the entries in the innermost sum, then the 1 row as the entries in the next sum times sum(np.transpose(B),0) and so on, but the value of the first sum (of row 0) needs to vary with each entry in row 1 since that sum still has indices dependent on our position in row 1, so on and so forth all the way up to sum k-i.
A sum which allows for a 'variable' filled in by each position of the array it's summing through would thusly do the trick, but I can't find anything along these lines in numpy and my attempts to hack one together have thus far failed -- my intuition says there is a solution that involves summing along the axes of a k-i dimensional array, but I haven't been able to make this precise yet. Any assistance is greatly appreciated.
One simple attempt to hard-code something like this would be:
for j0 in range(0,n0):
for j1 in range(0,n1):
....
Edit: (a vectorized version)
You could do something like this: (I didn't test it)
temp = np.ones(n[k-i])
for j in range(0,k-i):
temp = x[:n[k-i-1-j],:n[k-i-j]].T#(y[:n[k-i-j]]*temp)
result = x[alpha,:n[0]]#(y[:n[0]]*temp)
The basic idea is that you try to press it into a matrix-vector form. (note that this is python3 syntax)
Edit: You should note that you need to change the "k-1" to where the innermost sum is (I just did it for all sums up to index k-i)
This is 95% identical to #sehigle's answer, but includes a generic N vector:
def nested_sum(XX, Y, N, alpha):
intermediate = np.ones(N[-1], dtype=XX.dtype)
for n1, n2 in zip(N[-2::-1], N[:0:-1]):
intermediate = np.sum(XX[:n1, :n2] * Y[:n2] * intermediate, axis=1)
return np.sum(XX[alpha, :N[0]] * Y[:N[0]] * intermediate)
Similarly, I have no knowledge of the expression, so I'm not sure how to build appropriate tests. But it runs :\

trying to sum two arrays

I'm trying to code something like this:
where x and y are two different numpy arrays and the j is an index for the array. I don't know the length of the array because it will be entered by the user and I cannot use loops to code this.
My main problem is finding a way to move between indexes since i would need to go from
x[2]-x[1] ... x[3]-x[2]
and so on.
I'm stumped but I would appreciate any clues.
A numpy-ic solution would be:
np.square(np.diff(x)).sum() + np.square(np.diff(y)).sum()
A list comprehension approach would be:
sum([(x[k]-x[k-1])**2+(y[k]-y[k-1])**2 for k in range(1,len(x))])
will give you the result you want, even if your data appears as list.
x[2]-x[1] ... x[3]-x[2] can be generalized to:
x[[1,2,3,...]-x[[0,1,2,...]]
x[1:]-x[:-1] # ie. (1 to the end)-(0 to almost the end)
numpy can take the difference between two arrays of the same shape
In list terms this would be
[i-j for i,j in zip(x[1:], x[:-1])]
np.diff does essentially this, a[slice1]-a[slice2], where the slices are as above.
The full answer squares, sums and squareroots.

Array: Ascending and Multiplication Table

How to arrange 5 integers using array in ascending order, no use of sort()
then 5x5 multiplication table using array too, like using list, array append.
I'm going to take a stab at what I believe you're asking, mostly because I hope it's educational. You're lucky I'm procrastinating studying at the moment.
Sorting, because who likes entropy anyway?
Bubbles!
Your first task is to look at the bubble sort, a sorting algorithm that's as simple to code as it is to understand. (It performs poorly with large arrays due to its O(n2) performance but is probably among the first sorts a lot of people encounter.) I highly, highly suggest you understand the algorithm before even thinking about looking at code.
How does it work?
Start at the beginning! Look at the first pair of numbers. If they're in the wrong order, swap them. Increment your starting position by 1 and repeat until the end of the array.
What would this look like in Python?
I'm glad you asked. You need to loop through the whole array and swap whenever appropriate. Thankfully Python makes swapping very easy, allowing you to pull tricks like a, b = b, a. We can (hopefully quickly) write down some code to do what we want:
def bubble_sort(array):
for i in xrange(len(array)):
for j in xrange(len(array) - i - 1):
if array[j] > array[j + 1]:
array[j], array[j + 1] = array[j + 1], array[j]
return array
This should be straightforward and follows the sorting procedure directly. Pass in an array (or list of numbers) and it will return an array sorted in ascending order.
Multiplication Table
I'm assuming you mean something like this table that you learn in first grade. The requirement I'm imposing on your vague wording is that we want to return a 2D array where the first row is multiples of 0, the second is multiples of 1, etc. This goes for the columns as well, since multiplication tables are symmetric between rows and columns. There are a number of possible approaches, but I'm only going to consider the one I personally find the most elegant and Pythonic. Python comes packed with great list comprehension, so why not make use of it? Try this:
table = [[x*y for x in xrange(6)] for y in xrange(6)]
This creates a 6x6 matrix, i.e. the multiplication table from 0–5. Take some time to really understand this code. I think that list comprehension is absolutely fundamental to Python and is something that sets it apart. If you look at the (i, j)th element of the array, you'll see that it equals ij. For example, table[3][2] == 6 is true.
I desperately hope you learned something useful from this. Next time you post a question, hopefully you'll give us more to work on.

How to find the index of an array within an array

I have created an array in the way shown below; which represents 3 pairs of co-ordinates. My issue is I don't seem to be able to find the index of a particular pair of co-ordinates within the array.
import numpy as np
R = np.random.uniform(size=(3,2))
R
Out[5]:
array([[ 0.57150157, 0.46611662],
[ 0.37897719, 0.77653461],
[ 0.73994281, 0.7816987 ]])
R.index([ 0.57150157, 0.46611662])
The following is returned:
AttributeError: 'numpy.ndarray' object has no attribute 'index'
The reason I'm trying to do this is so I can extend a list, with the index of a co-ordinate pair, within a for-loop.
e.g.
v = []
for A in R:
v.append(R.index(A))
I'm just not sure why the index function isn't working, and can't seem to find a way around it.
I'm new to programming so excuse me if this seems like nonsense.
index() is a method of the type list, not of numpy.array. Try:
R.tolist().index(x)
Where x is, for example, the third entry of R. This first convert your array into a list, then you can use index ;)
You can achieve the desired result by converting your inner arrays (the coordinates) to tuples.
R = map(lambda x: (x), R);
And then you can find the index of a tuple using R.index((number1, number2));
Hope this helps!
[Edit] To explain what's going on in the code above, the map function goes through (iterates) the items in the array R, and for each one replaces it with the return result of the lambda function.
So it's equivalent to something along these lines:
def someFunction(x):
return (x)
for x in range(0, len(R)):
R[x] = someFunction(R[x])
So it takes each item and does something to it, putting it back in the list. I realized that it may not actually do what I thought it did (returning (x) doesn't seem to change a regular array to a tuple), but it does help your situation because I think by iterating through it python might create a regular array out of the numpy array.
To actually convert to a tuple, the following code should work
R = map(tuple, R)
(credits to https://stackoverflow.com/a/10016379/2612012)
Numpy arrays don't an index function, for a number of reasons. However, I think you're wanting something different.
For example, the code you mentioned:
v = []
for A in R:
v.append(R.index(A))
Would just be (assuming R has unique rows, for the moment):
v = range(len(R))
However, I think you might be wanting the built-in function enumerate. E.g.
for i, row in enumerate(R):
# Presumably you're doing something else with "row"...
v.append(i)
For example, let's say we wanted to know the indies where the sum of each row was greater than 1.
One way to do this would be:
v = []
for i, row in enumerate(R)
if sum(row) > 1:
v.append(i)
However, numpy also provides other ways of doing this, if you're working with numpy arrays. For example, the equivalent to the code above would be:
v, = np.where(R.sum(axis=1) > 1)
If you're just getting started with python, focus on understanding the first example before worry too much about the best way to do things with numpy. Just be aware that numpy arrays behave very differently than lists.

Categories

Resources