Python - How to Sort Multidimensional List to Two-Dimensional List

Python - How to sort multidimensional list to two-dimensional list?

The idea is basically the same that the one in @TerryA answer, but using setdefault and checking at the end of the for loop if something of the depth was added:

lst = [8, [6, 7, [-1], [4, [[10]]], 2], 1]


def depths(l):
def flatten(l, start=0, depth={}):

for e in l:
if isinstance(e, list):
flatten(e, start=start + 1, depth=depth)
else:
depth.setdefault(start, []).append(e)
if start not in depth:
depth[start] = []

d = {}
flatten(l, depth=d)

return [d[i] for i in range(max(d) + 1)]


result = depths(lst)
print(result)

Output

[[8, 1], [6, 7, 2], [-1, 4], [], [10]]

How to sort two dimensional list while giving priority along one of the dimension

You need to consider both values in the same sort key. Normally, Python would sort by the [0] value, then by the [1] value. We can make use of this by creating a key that reverses the values:

sorted(twod_list,key=lambda l:(l[1], l[0]))

Now Python will sort first according to the [0] of the key, which is [1] of the original, and then according to the [1] of the key, which is [0] of the original.

How to sort a 2 dimensional list in python

Well, i dug a little in stackoverflow questions and found the most suitable answer for me:
https://stackoverflow.com/a/7588949/13077523

From the Python documentation wiki, I think you can do:

a = ([[1, 2, 3], [4, 5, 6], [0, 0, 1]]);
a = sorted(a, key=lambda a_entry: a_entry[1])
print a
The output is:

[[[0, 0, 1], [1, 2, 3], [4, 5, 6]]]

But what i instead did is:

get_results = search(input('Please enter a movie name: '))
get_results = sorted(get_results, key=lambda a_entry: a_entry['year'])
count = -1
table = []
for a in get_results:
count += 1
entry = [count, a['title'], a['year']]
table.append(entry)

headers = ['SlNo', "Title", "Year"]
table = tabulate(table, headers, tablefmt='psql')
table = '\n'.join(table.split('\n')[::-1])
click.echo(table)

Which worked perfectly for me!

how to sort a multidimensional array with one column in ascending order and another column in descending order?

You can use the key but with a small change, and using - counts as "descending" (negative numbers always come before positive numbers in an ascending order sort). So you don't have to use the reverse parameter at all.

>>> sorted(students, key = lambda x:(-x[2], x[1]))
[[2, 'Rose', 13], [3, 'Jack', 12], [5, 'Sam', 12], [1, 'Tom', 10], [4, 'Joy', 8]]

How to sort multidimensional array by column?

Yes. The sorted built-in accepts a key argument:

sorted(li,key=lambda x: x[1])
Out[31]: [['Jason', 1], ['John', 2], ['Jim', 9]]

note that sorted returns a new list. If you want to sort in-place, use the .sort method of your list (which also, conveniently, accepts a key argument).

or alternatively,

from operator import itemgetter
sorted(li,key=itemgetter(1))
Out[33]: [['Jason', 1], ['John', 2], ['Jim', 9]]

Read more on the python wiki.

Sort two dimensional list python

I'm not sure this is a sorting problem; it's more of a grouping one (or optimization?)

Sorting requires some criteria for putting the [45,205] list before [42,206]. key works if you can come up with one number that represents the desired order.

For example calculate the distance from the origin

A = np.array(a) creates a numpy array:

In [346]: A
Out[346]:
array([[ 42, 206],
[ 45, 40],
[ 45, 205],
[ 46, 41],
[ 46, 205],
[ 47, 40],
[ 47, 202],
[ 48, 40],
[ 48, 202],
[ 49, 38]])

distance or radius in polar coordinates is sum of squares (sqrt isn't needed for this purpose). Applying argsort to this ranks the points by distance from origin.

In [347]: np.sum(A**2,axis=1)
Out[347]: array([44200, 3625, 44050, 3797, 44141, 3809, 43013, 3904, 43108, 3845])
In [348]: r = np.sum(A**2,axis=1)
In [349]: idx = np.argsort(r)
In [350]: idx
Out[350]: array([1, 3, 5, 9, 7, 6, 8, 2, 4, 0], dtype=int32)
In [351]: A[idx,:]
Out[351]:
array([[ 45, 40],
[ 46, 41],
[ 47, 40],
[ 49, 38],
[ 48, 40],
[ 47, 202],
[ 48, 202],
[ 45, 205],
[ 46, 205],
[ 42, 206]])

The list equivalent operation uses a key function like

def foo(xy):
x,y=xy
return x**2+y**2
In [356]: sorted(a, key=foo)
Out[356]:
[[45, 40],
[46, 41],
[47, 40],
[49, 38],
[48, 40],
[47, 202],
[48, 202],
[45, 205],
[46, 205],
[42, 206]]

Pairwise distances

In numpy it's fairly easy to come up with pairwise distance (even easier with one of the scipy tools). But what would you do with those? What defines order based on such distances?

For example to use the kind of iteration that we are often asked to 'vectorize':

In [369]: D = np.zeros((10,10))
In [370]: for i in range(10):
...: for j in range(i,10):
...: D[i,j] = np.sqrt(sum((A[i,:]-A[j,:])**2))
# D[i,j] = np.linalg.norm(A[i,:]-A[j,:])

In [372]: D.astype(int)
Out[372]:
array([[ 0, 166, 3, 165, 4, 166, 6, 166, 7, 168],
[ 0, 0, 165, 1, 165, 2, 162, 3, 162, 4],
[ 0, 0, 0, 164, 1, 165, 3, 165, 4, 167],
[ 0, 0, 0, 0, 164, 1, 161, 2, 161, 4],
[ 0, 0, 0, 0, 0, 165, 3, 165, 3, 167],
[ 0, 0, 0, 0, 0, 0, 162, 1, 162, 2],
[ 0, 0, 0, 0, 0, 0, 0, 162, 1, 164],
[ 0, 0, 0, 0, 0, 0, 0, 0, 162, 2],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 164],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

is a matrix of distances, rounded for ease of display.

numpy has a lexical sort. We could use that to sort on the 2nd coordinate first, and then the 1st coor. That would group all those 200's together:

In [375]: np.lexsort(A.T)
Out[375]: array([9, 1, 5, 7, 3, 6, 8, 2, 4, 0], dtype=int32)
In [376]: A[_,:]
Out[376]:
array([[ 49, 38],
[ 45, 40],
[ 47, 40],
[ 48, 40],
[ 46, 41],
[ 47, 202],
[ 48, 202],
[ 45, 205],
[ 46, 205],
[ 42, 206]])

pairwise distances with that sorted array look like:

array([[  0,   4,   2,   2,   4, 164, 164, 167, 167, 168],
[ 0, 0, 2, 3, 1, 162, 162, 165, 165, 166],
[ 0, 0, 0, 1, 1, 162, 162, 165, 165, 166],
[ 0, 0, 0, 0, 2, 162, 162, 165, 165, 166],
[ 0, 0, 0, 0, 0, 161, 161, 164, 164, 165],
[ 0, 0, 0, 0, 0, 0, 1, 3, 3, 6],
[ 0, 0, 0, 0, 0, 0, 0, 4, 3, 7],
[ 0, 0, 0, 0, 0, 0, 0, 0, 1, 3],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

Search over permutations

Another way of thinking of this problem is as a search problem, for example seeking to find the order of points that minimizes the 'travel' distance, i.e. the sum of distances between successive points.

With the original a (A), the distance (with default np.linalg.norm method) between successive points is

In [407]: np.linalg.norm(A[1:]-A[:-1],axis=1)
Out[407]:
array([ 166.02710622, 165. , 164.00304875, 164. ,
165.00303028, 162. , 162.00308639, 162. ,
164.00304875])

and their sum:

In [408]: _.sum()
Out[408]: 1474.0393203904973

With the lexsort order

In [410]: np.linalg.norm(A1[1:]-A1[:-1],axis=1)
Out[410]:
array([ 4.47213595, 2. , 1. , 2.23606798,
161.00310556, 1. , 4.24264069, 1. ,
4.12310563])
In [411]: _.sum()
Out[411]: 181.07705580534656

Clearly this has better clustering, mainly based on the 2nd column values.

Your sorted_a improves this sum a bit:

In [414]: sortedA = np.array(sorted_a)
In [415]: np.linalg.norm(sortedA[1:]-sortedA[:-1],axis=1)
Out[415]:
array([ 3.16227766, 4.12310563, 3.16227766, 1. ,
162.0277754 , 1.41421356, 1.41421356, 1. ,
2.23606798])
In [416]: _.sum()
Out[416]: 179.53993144488973

A brute force solution is to try all the permutations, and pick the one that minimizes this sum.

How to sort 2d array by row in python?

Python, per se, has no "2d array" -- it has (1d) lists as built-ins, and (1d) arrays in standard library module array. There are third-party libraries such as numpy which do provide Python-usable multi-dimensional arrays, but of course you'd be mentioning such third party libraries if you were using some of them, rather than just saying "in Python", right?-)

So I'll assume that by "2d array" you mean a list of lists, such as:

lol = [ range(10), range(2, 12), range(5, 15) ]

or the like -- i.e. a list with 3 items, each item being a list with 10 items, and the "second row" would be the sublist item lol[1]. Yeah, lots of assumptions, but your question is so maddeningly vague that there's no way to avoid making assumptions - edit your Q to clarify with more precision, and an example!, if you dislike people trying to read your mind (and probably failing) as you currently make it impossible to avoid.

So under these assumptions you can sort each of the 3 sublists in the order required to sort the second one, for example:

indices = range(10)
indices.sort(key = lol[1].__getitem__)
for i, sublist in enumerate(lol):
lol[i] = [sublist[j] for j in indices]

The general approach here is to sort the range of indices, then just use that appropriately sorted range to reorder all the sublists in play.

If you actually have a different problem, there will of course be different solutions;-).

Sorting a 2D list in python with conditions

Python's sort function is stable, which means that if two elements compare equal to each other, their relative positions don't change. Elements only switch positions if they compare unequal to each other.

Additionally, sorting takes an optional key parameter, which is a function that determines which values the sort should compare. You can define a full function for this, but it's common to define a short lambda function if you're only going to use it once.

Put these together, and you can first sort the lists by their second elements, then sort them a second time by their first elements. The relative positions from the first sort will be maintained after the second.

a = [
['abc', 5],
['abd', 21],
['abb', 10],
['abc', 3],
['abb', 15],
['abd', 20]
]

# Sort by second element first, in descending order
a = sorted(a, key=lambda x: x[1], reverse=True)

# Then sort by first element, in ascending order
a = sorted(a, key=lambda x: x[0])

print(a) # [['abb', 15], ['abb', 10], ['abc', 5], ['abc', 3], ['abd', 21], ['abd', 20]]


Related Topics



Leave a reply



Submit