简体   繁体   中英

Matching dictionary key tuple items in a comprehension

When using a comprehension expression that scans a dictionary, if I know the keys of the dictionary are simple 2 items tuples, is it possible to "expand" them to named variables?

eg if I have:

d = { ('car','blue') : 24,
      ('car',    'red'  ): 5,
      ('plant',     'green'): 12,
      ('box','blue' ): 3
}

I know I can do

[d[key] for key in d.keys() if key[1]=='blue']

and get

[24, 3]

But this loses a lot of the semantics and I wanted to know if I can somehow do something more like:

[count for {(object,color):count} in d if color=='blue']

(which I know does not work). Also I don't understand why the error returned for the last expression is:

SyntaxError: can't assign to literal

I would go with:

[count for (object, color), count in d.items() if color == 'blue']

as the clearest solution.

The error you are getting is because when using the in keyword python is trying to assign an item from d dictionary to {(object,color):count} which is a literal means create a new dictionary. instead, use (object, color), count as this is how python expands dict items.

You can't quite do that, but you can get close if you "upgrade" your keys to namedtuples . I'm using 'kind' as the name of the first item in the namedtuple because object is a built-in type, and although we can safely use it here I think it'd make the code a bit confusing.

from collections import namedtuple

d = { ('car', 'blue') : 24,
      ('car', 'red'): 5,
      ('plant', 'green'): 12,
      ('box', 'blue'): 3
}

Thing = namedtuple('Thing', ('kind', 'color'))
d = {Thing(*key): count for key, count in d.items()}
print(d)

lst = [count for key, count in d.items() if key.color == 'blue']
print(lst)
lst = [count for key, count in d.items() if key.kind == 'car']
print(lst)

output

{Thing(kind='car', color='blue'): 24, Thing(kind='car', color='red'): 5, Thing(kind='plant', color='green'): 12, Thing(kind='box', color='blue'): 3}
[24, 3]
[24, 5]

Actually, you don't really need namedtuples, although I think they make it a bit nicer. ;)

d = { ('car', 'blue') : 24,
      ('car', 'red'): 5,
      ('plant', 'green'): 12,
      ('box', 'blue'): 3
}

lst = [count for (kind, color), count in d.items() if color == 'blue']
print(lst)

It is possible. Try:

  [d.get((object,color)) for object,color in d.keys() if color == 'blue']

this returns

  [24, 3]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM