Indices of all values in an array - python

I have a matrix A. I would like to generate the indices of all the values in this matrix.
A=np.array([[1,2,3],[4,5,6],[7,8,9]])
The desired output should look like:
[(0,0),(0,1),(0,2),(1,0),(1,1),(2,1),(2,0),(2,1),(2,2)]

You can use:
from itertools import product
list(product(*map(range, A.shape)))
This outputs:
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
Explanation:
A.shape gives the dimensions of the array. For each dimension, we create a range() that generates all of the numbers between 0 and the length of a given dimension. We use map() to perform this for each dimension of the array. Finally, we unpack all of these ranges into the arguments of itertools.product() to create the Cartesian product among all these ranges.
Notably, the use of list unpacking and map() means that this approach can handle ndarrays with an arbitrary number of dimensions. At the time of posting this answer, all of the other answers cannot be immediately extended to a non-2D array.

This should work.
indices = []
for i in range(len(A)):
for j in range(len(A[i])):
indices.append((i,j))

Heres a way of doing by using itertools combinations
from itertools import combinations
sorted(set(combinations(tuple(range(A.shape[0])) * 2, 2)))
combinations chooses two elements from the list and pairs them, which results in duplication, so converting it to set to remove duplications and then sorting it.

This line of list comprehension works. It probably isn't as fast as using itertools, but it does work.
[(i,j) for i in range(len(A)) for j in range(len(A[i]))]

Using numpy only you can take advantage of ndindex
list(np.ndindex(A.shape))
or unravel_index:
list(zip(*np.unravel_index(np.arange(A.size), A.shape)))
Output:
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
NB. The second option enables you to pass a order='C' (row-major) or order='F' (column-major) parameter to get a different order of the coordinates
Example on A = np.array([[1,2,3],[4,5,6]])
order='C' (default):
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]
order='F':
[(0, 0), (1, 0), (0, 1), (1, 1), (0, 2), (1, 2)]

Related

Python zip function in Matlab

I have some Python code that I would like to run in Matlab. Suppose you have two lists of the same length:
x = [0, 2, 2, 5, 8, 10]
y = [0,2, 4, 7, 3, 3]
P = np.copy(y)
P.sort()
P = np.unique(P, axis=0) # P = [0 2 3 4 7] Takes the list y, sorts it and removes repeated elements
s = list(zip(x,y)) #match list x with y: s = [(0, 0), (2, 2), (2, 4), (5, 7), (8, 3), (10, 3)]
for y_1,y_2 in zip(P,P[1:]): # runs over (0, 2), (2, 3), (3, 4), (4, 7)
for v_1,v_2 in zip(s, s[1:]):
-- process --
Where in this case:
list(zip(s, s[1:])) = [((0, 0), (2, 2)), ((2, 2), (2, 4)), ((2, 4), (5, 7)), ((5, 7), (8, 3)), ((8, 3), (10, 3))]
I would like to translate this in Matlab but I don't know how to replicate the zip function. Any ideas on how I can do this?
MATLAB doesn’t have a zip, but you can accomplish the same thing in various ways. I think that the simplest translation of
for y_1,y_2 in zip(P,P[1:]):
...
is
for ii = 1:numel(P)-1
y_1 = P(ii);
y_2 = P(ii+1);
...
And in general, iterating over zip(x,y) is accomplished by iterating over indices 1:numel(x), then using the loop index to index into the arrays x and y.
Here's an implementation of Python's zip function in Matlab.
function out = zip(varargin)
% Emulate Python's zip() function.
%
% Don't actually use this! It will be slow. Matlab code works differently.
args = varargin;
nArgs = numel(args);
n = numel(args{1});
out = cell(1, n);
for i = 1:n
blah = cell(1, nArgs);
for j = 1:nArgs
if iscell(args{j})
blah(j) = args{j}(i);
else
blah{j} = args{j}(i);
end
end
out{i} = blah;
end
end
But don't use it; the performance will be lousy. In Matlab, you want to keep things in parallel primitive arrays instead, and use vectorized operations on those. Or, if you have to, iterate over array indexes.

Loop through list of tuples and unpack elements of each tuple

I have this list of two-value tuples
stake_odds=[(0, 1), (0, 2), (0, 5), (0, 10), (2, 1), (2, 2), **(2, 5)**, (2, 10), (5, 1), (5, 2), (5, 5), (5, 10), (10, 1), (10, 2), (10, 5), (10, 10)]
I have the following function where I want to put the tuple into an object method where it calculates the product (or minus product depending on the instance) of the two numbers in the tuple. If the product is positive, I want to append the tuple used to another list, pos_cases.
def function():
pos_cases=[]
x,y=stake_odds[9]
b1=bet1.payout(x,y)
if b1 > 0:
return b1, "b is greater than zero!"
pos_cases.append(stake_odds[9])
print(pos_cases)
print(function())
As you can see below I have to unpack the tuple into two variables before computing. I can do it by specifying the element of the list (stake_odds[9]), however I am looking for a way to generalize and loop through the list (stake_odds[i]) rather than going one by one.
The list in this example would be shortened to the following:
pos_cases =[(2, 1), (2, 2), (2, 5), (2, 10), (5, 1), (5, 2), (5, 5), (5, 10), (10, 1), (10, 2), (10, 5), (10, 10)]
How could I do this? The only thing I can think of is some nested for loop like:
for i in stake_odds:
for x,y in i:
return(x,y)
But this results in error >TypeError: cannot unpack non-iterable int object>.
Doesn't this work?:
def function():
pos_cases=[]
for x,y in stake_odds:
b1=bet1.payout(x,y)
if b1 > 0:
return b1, "b is greater than zero!"
pos_cases.append((x,y))
return pos_cases
print(function())

How to construct an array consisting of all paths of a given length in discretised 2D-space

Starting at (0,0) in the plane, given a positive integer n, I want to generate all paths consisting of n-1 steps away from (0,0). A step can be either one step to the right or one step up. For example, if n=4, then a path would be (0,0), (1,0), (1,1), (1,2). I'm currently using python
I've tried letting some parameter count the number of steps I'm taking and then using a while loop to restrict the number of steps, and for looping through my starting array [[[0,0]]].
def f(n):
A=[[[0,0]]]
s=0
while (int(s+1)<int(n)):
for i in A:
i.append([i[-1][0]+1,i[-1][1]])
A.append(i+[i[-1][0],i[-1][1]+1])
s+=1
return A
print f(2)
I'm getting an error 'int' object has no attribute 'getitem' on line 8. I also have a feeling that there are various other problems with the above code but am not too sure the best way to go about this
Welcome to Stackoverflow. This problem is ideally suited to recursive techniques.
If you have a path of length N at point P = (x, y) then you know it forms two
possible paths of length N+1, one to point (x+1, y) and one to point (x, y+1).
The only other thing you know is that there is one path of length zero at the starting point. Given that, you can compute the paths of length 1, the paths of length 2, and
so on. To separate the logic of path generation from the business of consuming the
paths I'd suggest using a generator function, allowing your logic to yield a
new path whenever is finds one. You can then iterate over this generator
to enumerate the paths. This appears to work:
def paths(in_path, N=1):
if N==1:
yield in_path
else:
x, y = in_path[-1]
yield from paths(in_path+[(x+1, y)], N-1)
yield from paths(in_path+[(x, y+1)], N-1)
for path in paths([(0, 0)], 4):
print(path)
The output I see is
[(0, 0), (1, 0), (2, 0), (3, 0)]
[(0, 0), (1, 0), (2, 0), (2, 1)]
[(0, 0), (1, 0), (1, 1), (2, 1)]
[(0, 0), (1, 0), (1, 1), (1, 2)]
[(0, 0), (0, 1), (1, 1), (2, 1)]
[(0, 0), (0, 1), (1, 1), (1, 2)]
[(0, 0), (0, 1), (0, 2), (1, 2)]
[(0, 0), (0, 1), (0, 2), (0, 3)]
which, gratifyingly, appears to include the example you gave.

Remove duplicate unordered tuples from list

In a list of tuples, I want to have just one copy of a tuple where it may be (x, y) or (y, x).
So, in:
# pairs = list(itertools.product(range(3), range(3)))
pairs = [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
the result should be:
result = [(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)] # updated pairs
This list of tuples is generated using itertools.product() but I want to remove the duplicates.
My working solution:
pairs = [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
result = []
for pair in pairs:
a, b = pair
# reordering in increasing order
temp = (a, b) if a < b else (b, a)
result.append(temp)
print(list(set(result))) # I could use sorted() but the order doesn't matter
How can this be improved?
You could use combinations_with_replacement
The code for combinations_with_replacement() can be also expressed as a subsequence of product() after filtering entries where the elements are not in sorted order (according to their position in the input pool)
import itertools
pairs = list(itertools.combinations_with_replacement(range(3), 2))
print(pairs)
>>> [(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)]
edit I just realized, your solution matches my solution. What you are doing is just fine. If you need to do this for a very large list, then there are some other options you may want to look into, like a key value store.
If you need to remove dupes more programatically, then you can use a function like this:
def set_reduce(pairs):
new_pairs = set([])
for x,y in pairs:
if x < y:
new_pairs.add((x,y))
else:
new_pairs.add((y,x))
return new_pairs
running this results in
>>>set_reduce(pairs)
set([(0, 1), (1, 2), (0, 0), (0, 2), (2, 2), (1, 1)])
This is one solution which relies on sparse matrices. This works for the following reasons:
An entry in a matrix cannot contain two values. Therefore, uniqueness is guaranteed.
Selecting the upper triangle ensures that (0, 1) is preferred above (1, 0), and inclusion of both is not possible.
import numpy as np
from scipy.sparse import csr_matrix, triu
lst = [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1),
(1, 2), (2, 0), (2, 1), (2, 2)]
# get row coords & col coords
d1, d2 = list(zip(*lst))
# set up sparse matrix inputs
row, col, data = np.array(d1), np.array(d2), np.array([1]*len(lst))
# get upper triangle of matrix including diagonal
m = triu(csr_matrix((data, (row, col))), 0)
# output coordinates
result = list(zip(*(m.row, m.col)))
# [(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)]

Visually Representing X and Y Values

I have a list of (x,y) values that are in a list like [(x,y),(x,y),(x,y)....]. I feel like there is a solution in matplotlib, but I couldn't quite get there because of my formatting. I would like to plot it as a histogram or line plot. Any help is appreciated.
You can quite easily convert a list of (x, y) tuples into a list of two tuples of x- and y- coordinates using the * ('splat') operator (see also this SO question):
>>> zip(*[(0, 0), (1, 1), (2, 4), (3, 9)])
[(0, 1, 2, 3), (0, 1, 4, 9)]
And then, you can use the * operator again to unpack those arguments into plt.plot
>>> plt.plot(*zip(*[(0, 0), (1, 1), (2, 4), (3, 9)]))
or even plt.bar
>>> plt.bar(*zip(*[(0, 0), (1, 1), (2, 4), (3, 9)]))
Perhaps you could try something like this (also see):
import numpy as np:
xs=[]; ys=[]
for x,y in xy_list:
xs.append(x)
ys.append(y)
xs=np.asarray(xs)
ys=np.asarray(ys)
plot(xs,ys,'ro')
Maybe not the most elegant solution, but it should work. Cheers, Trond

Categories

Resources