2

I'm trying to convert a matlab code into python and I faced a code like :

a=[1 2 3;4 5 6;7 8 9]
b=[1, 4, 8]
a(b)
//output :
ans :
1   4   8

this actually getting indexes from b and doing

a.item(x) #python

all I'm trying to ask is that, is there any way to do it in python ? Thanks. :)

Amir Esmaeili
  • 88
  • 2
  • 8
  • Probably a duplicate of [How can I compare two lists in python and return matches](https://stackoverflow.com/questions/1388818/how-can-i-compare-two-lists-in-python-and-return-matches). Sorry for not knowing how to set a question as a duplicate of another. – Chunpin May 22 '19 at 07:34
  • @Chunpin No, that's not the same problem. Also, `a(b)` gives `ans = 1 2 6`. – HansHirse May 22 '19 at 07:43

3 Answers3

2

Attention: At the time of writing this answer, the example given in the question is wrong. a(b) would result in:

ans =
   1   2   6

The provided MATLAB code uses linear indexing, which uses column-major order, whereas the stated a.item(x) Python function uses row-major order.

The ind2sub MATLAB function can convert linear indices to array indices. A similar numpy function is unravel_index.

Let's have a look at the following example code. Attention: Python uses 0-based indexing whereas MATLAB uses 1-based indexing.

import numpy as np

a = np.array([[10, 20, 30], [40, 50, 60], [70, 80, 90]])
b = np.array([0, 3, 7])

c = a[np.unravel_index(b, a.shape, 'F')]

print(a)
print(b)
print(c)

[[10 20 30]
 [40 50 60]
 [70 80 90]]

[0 3 7]

[10 20 60]
HansHirse
  • 18,010
  • 10
  • 38
  • 67
1

Use numpy

  • First flatten your 2D array into 1D
  • Then use the index in b to find data in a
  • Note: index in python starts from 0 matlab is 1, so you need to reduce the indices in b by 1
    import numpy as np

    a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    a = a.flatten()
    b = np.array([1, 4, 8])
    
    print(a[b-1])

    #array([1, 4, 8])

Community
  • 1
  • 1
Adam
  • 2,726
  • 1
  • 9
  • 22
  • MATLABs linear indexing uses column major order, whereas your solution uses row major order. Unfortunately, the example given in the question is already wrong on that part. – HansHirse May 22 '19 at 08:12
  • @HansHirse What do you mean by the given exemple is wrong on that part? Thought that was the same result he wanted to reproduce in python? not just an exemple – Adam May 22 '19 at 08:17
  • 1
    Please see my comment on the question: `a(b)` returns `1 2 6`, and not `1 4 8` as stated by the questioner. So, in the end, it's not clear, if the author wants to mimic the (correct) MATLAB functioning (column-major order indexing), or the given row-major order indexing, which then wouldn't be the proper MATLAB way. – HansHirse May 22 '19 at 08:20
0

In an Octave session:

>> a=[1 2 3;4 5 6;7 8 9]
a =

   1   2   3
   4   5   6
   7   8   9

>> b=[1, 4, 8]
b =

   1   4   8

>> a(b)
ans =

   1   2   6

This isn't the kind of behavior that I recall getting in MATLAB, but then I'm not in the habit of using index values greater than the dimensions. Evidently it is picking the items in a flattened matrix

>> reshape(a,1,9)
ans =

   1   4   7   2   5   8   3   6   9

>> reshape(a,1,9)(b)
ans =

   1   2   6

In Python/numpy indexing is done with [] instead of (). It is also 0 based, not 1.

In [56]: a = np.arange(1,10).reshape(3,3)                                                                
In [57]: a                                                                                               
Out[57]: 
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
In [58]: b=[0,3,7]                                                                                       
In [59]: a.ravel(order='F')[b]                                                                           
Out[59]: array([1, 2, 6])
In [60]: a.ravel(order='F')                                                                              
Out[60]: array([1, 4, 7, 2, 5, 8, 3, 6, 9])

To get the same values in numpy I had to specfify order F when flattening the array. That way it 'scans' the values in the column major order that MATLAB uses.

Without the order F, the default scan order is row major:

In [61]: a.ravel()                                                                                       
Out[61]: array([1, 2, 3, 4, 5, 6, 7, 8, 9])
In [62]: a.ravel()[b]                                                                                    
Out[62]: array([1, 4, 8])

I could also get the order F when initially reshaping a:

In [67]: a = np.arange(1,10).reshape(3,3,order='F')                                                      
In [68]: a                                                                                               
Out[68]: 
array([[1, 4, 7],
       [2, 5, 8],
       [3, 6, 9]])
In [69]: a.flat[b]                                                                                       
Out[69]: array([1, 2, 6])

===

In MATLAB/Octave, we can get the 2d indices with:

>> [r,c] = ind2sub([3,3],b)
r =

   1   1   2

c =

   1   2   3

>> a(1,1), a(1,2), a(2,3)
ans =  1
ans =  2
ans =  6

The same unraveling in numpy (applied to the order F version of a):

In [75]: np.unravel_index(b, (3,3))                                                                      
Out[75]: (array([0, 1, 2]), array([0, 0, 1]))
In [76]: a[_]                    # using the Out[75] line as index                                                                        
Out[76]: array([1, 2, 6])
In [77]: a[0,0],a[1,0],a[2,1]            # equivalently                                                                
Out[77]: (1, 2, 6)
hpaulj
  • 221,503
  • 14
  • 230
  • 353