0

I want to have an array act on a dictionary and return me the corresponding values. Rather than loop through it would be nice to do that in a pythonic way ie something like

results[:] = dict[np_vec[:]]

That doesn't work though, I was hoping maybe there is a method I'm not aware of?

In this case the np_vec has integers which correspond to a key in the dict, while the values are tuples and I would want to have a list of them in results.

1 Answer 1

1

The most straight forward Pythonic (i.e. uses good Python syntax) method is

results = [dict[value] for value in np_vec]

This needs refinement if dict might not have value.

Can I use a list comprehension on a list of dictionaries if a key is missing?

But perhaps you are hoping for something that passes as a vectorized numpy expression. The sticking point is that a dictionary will only access one key at a time

Another possibility is to use dict.keys() to get a list of keys, and use numpy methods to match np_vec with this list. No guarantee that this will be faster.

in1d doc

> in1d(a, b) is roughly equivalent to np.array([item in b for item in a]).

I'm thinking of something like (but details may be off)

 keys = dict.keys()
 values = dict.values()    
 mask = np.in1d(dict.keys(), np_vec)
 result = values[mask]

Working code using arrays:

A dictionary with numeric keys, tuple values:

In [302]: adict={k:v for k,v in zip([0,1,2,3,4,5],[(0,1),(1,2),(2,3),(3,4),(4,5)])}
In [303]: adict
Out[303]: {0: (0, 1), 1: (1, 2), 2: (2, 3), 3: (3, 4), 4: (4, 5)}

Array of keys we want to fetch

In [304]: npvec=np.arange(4)

Lists from dictionary:

In [305]: keys=list(adict.keys())
In [308]: values=list(adict.values())
In [309]: values
Out[309]: [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)]

mask - keys we want to pull

In [310]: mask=np.in1d(keys,npvec)
In [311]: mask
Out[311]: array([ True,  True,  True,  True, False], dtype=bool)

To apply the mask in one step, we have to use an array; keys[mask] does not work:

In [313]: np.array(keys)[mask]
Out[313]: array([0, 1, 2, 3])

The same would work if values were simple numbers, but they are tuples.

In [314]: np.array(values)[mask]
Out[314]: 
array([[0, 1],
       [1, 2],
       [2, 3],
       [3, 4]])

We could turn that 2d array back into a list of tuples.

But to preserve tuples (or other general Python object values), we have to do something more complicated, e.g.

In [315]: varray=np.empty(len(values),dtype=object)
In [317]: for i in range(5):varray[i]=values[i]
In [318]: varray
Out[318]: array([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)], dtype=object)

Now we can apply the mask and get the right set of values.

In [319]: varray[mask]
Out[319]: array([(0, 1), (1, 2), (2, 3), (3, 4)], dtype=object)

Contrast that with the simple list comprehension solution:

In [321]: [adict[v] for v in npvec]
Out[321]: [(0, 1), (1, 2), (2, 3), (3, 4)]

Sometimes trying to be more Pythonic, err numpy-onic, just isn't worth the extra work.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.