johnhenry
johnhenry

Reputation: 1333

sorting list of lists and getting indices in unsorted list

These are the logical steps that I need to perform on my list of lists

a = [[5,2],[7,4],[0,3]]
  1. sort the list of lists in such a way that the output looks something like

    7,5,4,3,2,0
    
  2. take the coordinates of the sorted elements in the original list, which in this case should produce as output

    (1,0)
    (0,0)
    (1,1)
    (2,1)
    (0,1)
    (2,0)
    

I tried using of sort, sorted and argwhere in different ways but I am not getting sensible results, I guess first of all because sort and sorted can sort a list following only one axis at a time

Upvotes: 8

Views: 1668

Answers (5)

Kasravnd
Kasravnd

Reputation: 107347

Use Numpy, which is pretty much faster than regular python code when you are dealing with larger arrays:

In [21]: a = np.array([[5,2],[7,4],[0,3]])
In [22]: x, y = np.unravel_index((-a).argsort(axis=None), a.shape)

In [23]: indices = np.column_stack((x, y))

In [24]: indices
Out[24]: 
array([[1, 0],
       [0, 0],
       [1, 1],
       [2, 1],
       [0, 1],
       [2, 0]])

In [25]: a[x, y]
Out[25]: array([7, 5, 4, 3, 2, 0])

Upvotes: 2

kezzos
kezzos

Reputation: 3221

You can use a series of list comprehensions and zip blocks, although the readability suffers:

n, idxs = zip(*sorted(zip([i for sl in a for i in sl], [(col, row) for col in range(len(a)) for row in range(len(a[col]))]), key=lambda x: x[0], reverse=True))

print n, idxs
>>> (7, 5, 4, 3, 2, 0) ((1, 0), (0, 0), (1, 1), (2, 1), (0, 1), (2, 0))

If you need a dict, just replace the zip(*..) layer with dict()

Upvotes: 2

PM 2Ring
PM 2Ring

Reputation: 55499

This code will work for a list of lists. The internal lists don't have to be the same length.

At each level we iterate over a list using enumerate to get the list item and its index. At the top level, each item is another list, and the inner loop iterates over each of those lists to get their indices and values, storing the indices (as a tuple) in a tuple that also contains the value. We then sort the resulting list of tuples (b) on the values, and then split it using zip into a tuple of all the indices and a tuple of the values.

from operator import itemgetter

a = [[5, 2], [7, 4], [0, 3]]

b = [((i, j), v) for i, t in enumerate(a) for j, v in enumerate(t)]
b.sort(key=itemgetter(-1), reverse=True)
print(b)
coords, vals = zip(*b)
print(vals)
print(coords)

output

[((1, 0), 7), ((0, 0), 5), ((1, 1), 4), ((2, 1), 3), ((0, 1), 2), ((2, 0), 0)]
(7, 5, 4, 3, 2, 0)
((1, 0), (0, 0), (1, 1), (2, 1), (0, 1), (2, 0))

Upvotes: 8

vks
vks

Reputation: 67988

You can flatten the list and then use it to sort and find indices.

a = [[5,2],[7,4],[0,3]]
c = reduce(lambda x, y: x+y, a)
b = sorted(c, reverse=True)
for i in b:
    print c.index(i)/2, c.index(i)%2

Output:

1 0 
0 0
1 1
2 1
0 1
2 0

Upvotes: 1

thefourtheye
thefourtheye

Reputation: 239643

Create a dictionary with the keys as the actual coordinates and the values as the numbers themselves, like this

>>> a = [[5, 2], [7, 4], [0, 3]]
>>> positions = {
...     (idx1, idx2): col
...     for idx1, row in enumerate(a)
...     for idx2, col in enumerate(row)
... }
>>> positions
{(0, 1): 2, (2, 0): 0, (0, 0): 5, (1, 0): 7, (1, 1): 4, (2, 1): 3}

Now, sort the keys (coordinates) of positions based on their values, like this

>>> sorted(positions, key=positions.get, reverse=True)
[(1, 0), (0, 0), (1, 1), (2, 1), (0, 1), (2, 0)]

Upvotes: 8

Related Questions