Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Permute a tuple by a list of indices

Tags:

python

tuples

I have a 3 element python tuple that I'm trying to sort or re-arrange using the indices of a 3-element list, and I want to know what the most concise way to do this is.

So far I've got:

my_tuple = (10, 20, 30)
new_positions = [2, 0, 1]
my_shuffled_tuple = my_tuple[new_positions[0]], my_tuple[new_positions[1]], my_tuple[new_positions[2]]
# outputs: (30, 10, 20)

I also get the same result if I do:

my_shuffled_tuple = tuple([my_tuple[i] for i in new_positions])

Is there a more concise way to create my_shuffled_tuple?

like image 495
tomr_stargazer Avatar asked Dec 19 '22 09:12

tomr_stargazer


2 Answers

One way to do this is with a generator expression as an argument to tuple, which accepts an iterable:

In [1]: my_tuple = (10, 20, 30)
   ...: new_positions = [2, 0, 1]
   ...: 

In [2]: my_shuffled_tuple = tuple(my_tuple[i] for i in new_positions)

In [3]: my_shuffled_tuple
Out[3]: (30, 10, 20)

If speed is an issue and you are working with a large amount of data, you should consider using Numpy. This allows direct indexing with a list or array of indices:

In [4]: import numpy as np

In [5]: my_array = np.array([10, 20, 30])

In [6]: new_positions = [2, 0, 1]  # or new_positions = np.array([2, 0, 1])

In [7]: my_shuffled_array = my_array[new_positions]

In [8]: my_shuffled_array
Out[8]: array([30, 10, 20])
like image 106
Bas Swinckels Avatar answered Jan 02 '23 16:01

Bas Swinckels


You can use operator.itemgetter like this:

from operator import itemgetter

my_tuple = (10, 20, 30)
new_positions = [2, 0, 1]

print itemgetter(*new_positions)(my_tuple)

If you will be accessing the elements of my_tuple (or other things too) in the new ordering a lot, you can save this itemgetter as a helper function:

access_at_2_0_1 = itemgetter(*new_positions)

and then access_at_2_0_1(foo) will be the same as tuple(foo[2], foo[0], foo[1]).

This is very helpful when you are trying to work with an argsort-like operation (where lots of arrays need to be re-accessed in a sort order that comes from sorting some other array). Generally, by that point you should probably be using NumPy arrays, but still this is a handy approach.

Note that as itemgetter relies on the __getitem__ protocol (derp) it is not guaranteed to work with all types of iterables, if that is important.

like image 29
ely Avatar answered Jan 02 '23 16:01

ely