3

I have a large number of strings that I would like to convert to integers. What is the most concise way to perform a dictionary lookup of a list in Python 3.7?

For example:

d = {'frog':1, 'dog':2, 'mouse':3}
x = ['frog', 'frog', 'mouse']
result1 = d[x[0]]
result2 = d[x]

result is equal to 1 but result2 is not possible:

TypeError                                 Traceback (most recent call last)
<ipython-input-124-b49b78bd4841> in <module>
      2 x = ['frog', 'frog', 'mouse']
      3 result1 = d[x[0]]
----> 4 result2 = d[x]

TypeError: unhashable type: 'list'

One way to do this is:

result2 = []
for s in x:
    result2.append(d[s])

which results in [1, 1, 3] but requires a for loop. Is that optimal for large lists?

Steve
  • 3,957
  • 2
  • 26
  • 50
  • What did you *expect* for `result2`? It's unclear what the output should be. Have you read the various other posts referring to that error? – jonrsharpe Feb 10 '19 at 22:34
  • 1
    Do you mean something like `[d[k] for k in x]`? – iz_ Feb 10 '19 at 22:40
  • @jonrsharpe The result should be `[1, 1, 3]`. Edited to provide a possible result. – Steve Feb 10 '19 at 22:43
  • @Tomothy32 Yes. Is this equivalent to the example or should I expected performance gains since your iterator can be sure of the size beforehand? – Steve Feb 10 '19 at 22:43
  • 1
    @Steve In general, list comprehensions are faster than for loops. Another option is `list(map(d.get, x))`. You should try every solution yourself to see what's best. From what I've tried, `itemgetter` is quickest. – iz_ Feb 10 '19 at 22:44
  • @Tomothy32 in general it is a *marginal* speed improvement that can almost be erased by simply caching the call to `result2.append`. The main advantages of list-comprehensions are clean code. – juanpa.arrivillaga Feb 10 '19 at 23:25
  • "but requires a for loop" It will always require a for-loop of some sort or other. – juanpa.arrivillaga Feb 10 '19 at 23:25

2 Answers2

9

Keys of a dict have to be hashable, which a list, such as x, is not, which is why you're getting the TypeError: unhashable type: 'list' error when you try to use x as a key to index the dict d.

If you're trying to perform bulk dictionary lookup you can use the operator.itemgetter method instead:

from operator import itemgetter
itemgetter(*x)(d)

This returns:

(1, 1, 3)
blhsing
  • 91,368
  • 6
  • 71
  • 106
4

If you're working with default python you can do a list comprehension:

result = [d[i] for i in x]

If you are open to numpy solutions you can use conditional replacement. This will probably be the fastest on large inputs:

import numpy as np

result = np.array(x)
for k, v in d.items(): result[result==k] = v

Finally pandas has a .replace

import pandas as pd

result = pd.Series(x).replace(d) 
Primusa
  • 13,136
  • 3
  • 33
  • 53