Note that there are some explanatory texts on larger screens.

plurals
  1. POComparing mixed dict elements against int, strings and floats
    text
    copied!<p>I would like to be able to make comparisons in a mixed-type dictionary (containing int, floats, strings, numpy.arrays). My minimal example has a list of dictionaries and I would like a function (or generator) to iterate over that list and pick out the elements (dicts) that contain key-value pairs as specified by **kwargs input to that function (or generator). </p> <pre class="lang-py prettyprint-override"><code>import re list_of_dicts = [{'s1':'abcd', 's2':'ABC', 'i':42, 'f':4.2}, {'s2':'xyz', 'i':84, 'f':8.4}] def find_list_element(**kwargs): for s in list_of_dicts: for criterion, criterion_val in kwargs.iteritems(): if type(criterion_val) is str: if re.match(criterion_val, s.get(criterion, 'unlikely_return_val')): yield s continue if s.get(criterion, None) == criterion_val: yield s print [a for a in find_list_element(i=41)] # [] print [a for a in find_list_element(i=42)] # [{'i': 42, 's2': 'ABC', 's1': 'abcd', 'f': 4.2}] print [a for a in find_list_element(s1='xyz')] # [] print [a for a in find_list_element(s2='xyz')] # [{'i': 84, 's2': 'xyz', 'f': 8.4}] print [a for a in find_list_element(s2='[a-z]')] # [{'i': 84, 's2': 'xyz', 'f': 8.4}] </code></pre> <p>My two problems with the above are:</p> <ol> <li><p>If the function asks for a a comparison that is a string, I would like to switch to regex matching (re.search or re.match) instead of plain string comparison. In the above code this is accomplished through the reviled type checking and it doesn't look all that elegant. Are there better solutions not involving type checking? Or maybe, this is a case where type checking is allowed in python?</p></li> <li><p><code>**kwargs</code> can of course contain more than one comparison. Currently I can only think of a solution involving some flags (<code>found = False</code> switched to a <code>found = True</code> and evaluated at the end of each iteration of <code>list_of_dicts</code>). Is there some clever way to accumulate the comparison results for each s before deciding on whether to yield it or not?</p></li> </ol> <p>Are there ways to make this whole walk through this collection of dicts prettier?</p> <p>PS: The actual use case for this involves the representation of acquired MRI datasets (BRUKER). Datasets are characterized through parameter files that I have converted to dicts that are part of the objects representing said scans. I am collecting these datasets and would like to further filter them based on certain criteria given by these parameter files. These parameters can be strings, numbers and some other less handy types.</p> <h2>UPDATE and Distilled Answer</h2> <p>If I head to come up with a consensus answer derived from the input by @BrenBarn and @srgerg it would be this</p> <pre><code>list_of_dicts = [{'s1':'abcd', 's2':'ABC', 'i':42, 'f':4.2}, {'s2':'xyz', 'i':84, 'f':8.4}] # just making up some comparison strategies def regex_comp(a,b): return re.match(a,b) def int_comp(a,b): return a==b def float_comp(a,b): return round(a,-1) == round (b,-1) pre_specified_comp_dict = {frozenset(['s1','s2']) : regex_comp, frozenset(['i']): int_comp, frozenset(['f']): float_comp} def fle_new(**kwargs): chosen_comps={} for key in kwargs.keys(): # remember, the keys here are frozensets cand_comp = [x for x in pre_specified_comp_dict if key in x] chosen_comps[key] = pre_specified_comp_dict[cand_comp[0]] matches = lambda d: all(k in d and chosen_comps[k](v, d[k]) for k, v in kwargs.items()) return filter(matches, list_of_dicts) </code></pre> <p>Now the only challenge would be to come up with a pain-free strategy of creating <code>pre_specified_comp_dict</code>.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload