How to filter list of dictionaries with matching values for a given key

16,882

Solution 1

Update: taking into account the reedited question of the OP:

def copyf(dictlist, key, valuelist):
      return [dictio for dictio in dictlist if dictio[key] in valuelist]

Solution 2

Probably not the best solution, but here we go:

>>> def copyf(data, key, allowed):
...     return filter(lambda x: key in x and x[key] in allowed, data)
... 
>>> dictlist = [{'first': 'James', 'last': 'Joule'}, {'first': 'James','last': 'Watt'},{'first': 'Christian','last': 'Doppler'}]
>>> copyf(dictlist, 'first', ('Christian',))
[{'last': 'Doppler', 'first': 'Christian'}]
>>> copyf(dictlist, 'last', ('Christian',))
[]
>>> copyf(dictlist, 'first', ('James',))
[{'last': 'Joule', 'first': 'James'}, {'last': 'Watt', 'first': 'James'}]
>>> 

Solution 3

Something like

new_dict = dict((k, v) for k,v in old_dict.items() if v in allowed_values)

?

Solution 4

Clean and neat, using filter and lambda

>>> def copyf(dictlist, key, valuelist):
...     filter(lambda d: d[key] in valuelist, dictlist)
Share:
16,882
Christopher O'Donnell
Author by

Christopher O'Donnell

Clueless.

Updated on July 29, 2022

Comments

  • Christopher O'Donnell
    Christopher O'Donnell almost 2 years

    With an interface like a = copyf(dictlist, key, valuelist).

    >>> dictlist = [{'first': 'James',
                     'last': 'Joule'},
                    {'first': 'James',
                     'last': 'Watt'},
                    {'first': 'Christian',
                     'last': 'Doppler'}]
    >>> valuelist = ['James', 'John']
    >>> x = copyf(dictlist, 'first', valuelist)
    >>> print(x)
    [{'first': 'James',
      'last': 'Joule'},
     {'first': 'James',
      'last': 'Watt'}]
    

    The dictlist is effectively a csv.DictReader instance.

  • kevpie
    kevpie about 13 years
    @plaes, you can turn the list comprehension into a generator expression by dropping the square brackets. This is in keeping with what your usage of iteritems() is trying to accomplish by avoiding the creation of an intermediate list.
  • plaes
    plaes about 13 years
    @kevpie: Thanks, will fix \o/
  • joaquin
    joaquin about 13 years
    you are removing all coincident values indepently of the key. The OP question said "matching values (for a given key) from a list" and actually gave 'key' as a function parameter. Maybe he changed his mind...or I misunderstood?
  • 9000
    9000 about 13 years
    in a dict, there can only be 0 or 1 value per given key. this sort of distracted me from the phrase you boldfaced. sorry! :)
  • joaquin
    joaquin about 13 years
    Well, you got the "accepted answer". Hope it is not due homework :-))
  • 9000
    9000 about 13 years
    Accepted answers change sometimes. Statistically it pays to give a superior answer even if the question already has a low-scored accepted answer (like mine here). Note that a fuller answer with the same approach now scores twice as high.
  • joaquin
    joaquin about 13 years
    @plaes, probably the OP was asking to filter by values not by keys. Note the function parameters given (dictionary, key, valuelist).
  • plaes
    plaes about 13 years
    @joaquin: Now that I look it again, it might be like that. :S
  • Christopher O'Donnell
    Christopher O'Donnell about 13 years
    Sorry guys, I was super tired when I posted the question and accepted this answer. This doesn't take "for a given key" into consideration.
  • Christopher O'Donnell
    Christopher O'Donnell about 13 years
    Sorry for the ambiguity, I have provided a usage example.
  • 9000
    9000 about 13 years
    It's totally ok. The right answer ought to be accepted, and a wrong answer, no matter how much upvoted, ought not.