internety
internety

Reputation: 374

python filtering list of dict by dict containing several key-value pairs as conditions

my example data:

list_of_dict =[{'cena': 23, 'nazwa': 'item1', 'param': 'pampam'},
               {'cena': 26, 'nazwa': 'item2', 'param': 'iko'   },
               {'cena': 26, 'nazwa': 'item2a','param': 'ik2'   },
               {'cena': 26, 'nazwa': 'item2b','param': 'ik2'   },
               {'cena': 17, 'nazwa': 'item3', 'param': 'etr'   },
               {'cena': 17, 'nazwa': 'item4', 'param': 'asdf'  }]

conditions =   {'cena': 26, 'param': 'ik2' }

I tried:

if conditions in list_of_dict:
    do_something()

it works, but only when whole conditions dict (every key) matches the one from dict list, I mean:

In [1]: exampleSet =      [{  'type' : 'type1', 'k' : 'kval'},
   ...:                    {  'type' : 'type2', 'k' : 'kv2' },
   ...:                    {  'type' : 'type2', 'k' : 'k3'  },
   ...:                    {  'type' : 'type3', 'k' : 'k3'  }]
   ...: 
   ...: conditions =       {  'type' : 'type1', 'k' : 'kval' }
   ...: 
   ...: 
   ...: conditions in exampleSet
   ...: 
Out[1]: True
In [2]: conditions =       {  'type' : 'type1' }

In [3]: conditions in exampleSet
Out[3]: False

while I am trying to match dictionaries with key-value pairs specified, (regardless of values/existence of unspecified ones) so

In [4]: exampleSet =      [{  'type' : 'type1', 'k' : 'kval'},
   ...:                    {  'type' : 'type2', 'k' : 'kv2' },
   ...:                    {  'type' : 'type2', 'k' : 'k3'  },
   ...:                    {  'type' : 'type3', 'k' : 'k3'  }]
   ...: 
   ...: conditions =       {  'type' : 'type2' }
   ...:
   ...: my_wanted_match( exampleSet, conditions )

has to return:

                     [{  'type' : 'type2', 'k' : 'kv2' },
                      {  'type' : 'type2', 'k' : 'k3'  }]

as a result.

can anyone gimme some hints on how to achieve this?

Upvotes: 5

Views: 3115

Answers (6)

Satya brata
Satya brata

Reputation: 21

list_of_dict =[{'cena': 23, 'nazwa': 'item1', 'param': 'pampam'},
               {'cena': 26, 'nazwa': 'item2', 'param': 'iko'   },
               {'cena': 26, 'nazwa': 'item2a','param': 'ik2'   },
               {'cena': 26, 'nazwa': 'item2b','param': 'ik2'   },
               {'cena': 17, 'nazwa': 'item3', 'param': 'etr'   },
               {'cena': 17, 'nazwa': 'item4', 'param': 'asdf'  }]

>Answers
 --------

res=list(filter(lambda list_of_dict:list_of_dict['cena']== 26 and list_of_dict['param']== 'ik2',list_of_dict))

for i in range(0,len(res)):
    if 'item2b' in res[i].values() :
        print(res[i])

Upvotes: -1

emvee
emvee

Reputation: 4449

It is a filter() you want - you want to filter your list-of-dicts based on some condition; returning only the entries that match all criteria.

>>> list_of_dict =[{'cena': 23, 'nazwa': 'item1', 'param': 'pampam'},
...                {'cena': 26, 'nazwa': 'item2', 'param': 'iko'   },
...                {'cena': 26, 'nazwa': 'item2a','param': 'ik2'   },
...                {'cena': 26, 'nazwa': 'item2b','param': 'ik2'   },
...                {'cena': 17, 'nazwa': 'item3', 'param': 'etr'   },
...                {'cena': 17, 'nazwa': 'item4', 'param': 'asdf'  }]

Set conditions:

>>> conditions = {'param':'iko'}

And do a one-line filter:

>>> filter(lambda item: all((item[k]==v for (k,v) in conditions.iteritems())), list_of_dict)
[{'cena': 26, 'param': 'iko', 'nazwa': 'item2'}]

Upvotes: 6

Eric
Eric

Reputation: 97631

sets come in handy here*:

has_match = any(set(condition.items()) <= set(d.items()) for d in listOfDict)

or for your second part:

the_matches = [
    d
    for d in listOfDict
    if set(condition.items()) <= set(d.items())
]

<= is the subset operator when applied to sets:

issubset(other)
set <= other

Test whether every element in the set is in other.

* provided you can ensure your values are hashable, ie not lists or dicts

Upvotes: 1

pkacprzak
pkacprzak

Reputation: 5629

Use list comprehension:

>>> list_of_dict =[{'cena': 23, 'nazwa': 'item1', 'param': 'pampam'},
...                {'cena': 26, 'nazwa': 'item2', 'param': 'iko'   },
...                {'cena': 26, 'nazwa': 'item2a','param': 'ik2'   },
...                {'cena': 26, 'nazwa': 'item2b','param': 'ik2'   },
...                {'cena': 17, 'nazwa': 'item3', 'param': 'etr'   },
...                {'cena': 17, 'nazwa': 'item4', 'param': 'asdf'  }]
>>> 
>>> conditions =   {'cena': 26, 'param': 'ik2' }
>>> [d for d in list_of_dict if all((k in d and d[k] == v) for k, v in conditions.items())]
[{'cena': 26, 'param': 'ik2', 'nazwa': 'item2a'}, {'cena': 26, 'param': 'ik2', 'nazwa': 'item2b'}]

Upvotes: 2

Alexander
Alexander

Reputation: 109616

This iterates through each dictionary in list_of_dict and returns those that have matching key value pairs to each condition.

matches = [one_dict for one_dict in list_of_dict if
           all(key in one_dict and conditions[key] == one_dict[key] 
               for key in conditions.keys())]
>>> matches
[{'cena': 26, 'nazwa': 'item2a', 'param': 'ik2'},
 {'cena': 26, 'nazwa': 'item2b', 'param': 'ik2'}]

Upvotes: 1

se7entyse7en
se7entyse7en

Reputation: 4294

def my_wanted_match(example_set, conditions):
    conditions = conditions.items()
    match = []
    for e in example_set:
        if all([c in set(e.items()) for c in conditions]):
            match.append(e)
    return match

or simply:

match = [e for e in example_set
         if all([c in set(e.items()) for c in set(conditions.items())])]

Upvotes: 0

Related Questions