2

I have a list with about 500 elements in it. For illustration I have:

list3 = [ 'a', 'b', 'c', 'a' ]

Where 'a', 'b', 'c' is name of the arrays as:

a = np.random.normal( 0, 1, ( 500, 20 ) )
b = np.random.normal( 0, 1, ( 500, 30 ) )
c = np.random.normal( 0, 1, ( 500, 30 ) )

I want to concatenate the arrays in the list in the order present in the list.

So, for my example I want to obtain:

C = np.concatenate( ( a, b, c, a ), 1 )

I don't have an idea how to approach this other than to store the arrays in a dictionary and then do a string search and concatenation in a for loop. Is there an elegant way to do this ?

Zanam
  • 4,607
  • 13
  • 67
  • 143

5 Answers5

1

If you want to be compact:

np.concatenate([dict(a=a, b=b, c=c)[x] for x in list3], 1)

Or to avoid the redundant dictionary creation:

by_label = dict(a=a, b=b, c=c)
np.concatenate([by_label[x] for x in list3], 1)
donkopotamus
  • 22,114
  • 2
  • 48
  • 60
1

You can use the globals object to get the arrays based on name.

globals()["a"] # array a

So can do

np.concatenate(tuple(globals()[x] for x in list3),1)
Matthew
  • 7,440
  • 1
  • 24
  • 49
  • This will work provided that the arrays to be concatenated are created in the global (or module level) scope. If they are created in a local scope (for instance inside a function call), then Brendan Abel's solution would be preferred. – Matthew Jan 13 '16 at 23:28
1

You can use the locals() dictionary to access the variables by name

d = locals()
np.concatenate([d[x] for x in list3], 1)
Brendan Abel
  • 35,343
  • 14
  • 88
  • 118
  • This does solve the OP's problem as stated, but it should be noted that this will not work if contained inside a function call. For example `def concatenate(listx): # return concatenated list based on listx` as locals will not contain global objects at that point. If the variables to be concatenated are created in the same scope, this will work. My solution suffers from a similar problem if the variables to be concatenated are created in a local scope. – Matthew Jan 13 '16 at 23:25
  • @Matthew True, it won't work inside a function only if the arrays are defined as global variables. – Brendan Abel Jan 13 '16 at 23:33
1

You can easily get such a dictionary of all local variables by calling the locals() function. For example, to look up a variable named 'a':

var = 'a'
locals()[var]

Since np.concatenate appears to take a tuple, you could use:

lc = locals()
C = np.concatenate(tuple(lc[var] for var in list3), 1)
Curt
  • 470
  • 3
  • 7
0

Why don't you store directly the variables instead of their names ? Like :

list3 = [a, b, c, a]
C = np.concatenate(list3, axis=1)

Or you can use eval() (which don't seems to be recommanded most of the time) :

list3 = ['a', 'b', 'c','a']
CC = np.concatenate([eval(i) for i in list3], axis=1)
mgc
  • 5,223
  • 1
  • 24
  • 37
  • Well ok for the downvote :) the use of `locals()` appears to be neater than `eval()`! – mgc Jan 13 '16 at 23:19
  • why is eval not recommended ? – Zanam Jan 13 '16 at 23:29
  • I guess because it could be risky to evaluate "whatever" expression (if the expression(s) to evaluate comes from an user input for example). See http://stackoverflow.com/questions/1832940/is-using-eval-in-python-a-bad-practice for more details for example (there is probably often a way to avoid using `eval` like here with `globals()` or `locals()` for example). – mgc Jan 13 '16 at 23:35
  • 1
    It will not deserve my answer but it seems to be an overhead to calling `eval` than looking up into `globals` : `%timeit np.concatenate([eval(i) for i in list3], axis=1)` return `10000 loops, best of 3: 116 µs per loop` and `%timeit gbl=globals();np.concatenate(tuple(gbl[x] for x in list3),1)` return `10000 loops, best of 3: 74.2 µs per loop` – mgc Jan 14 '16 at 00:17