0

Given a list of dictionaries:

the_list = [{k1:v1,k2:v2}, {k1:v3, k3:v4}, {k1:v5,k2:v6},{k3:v7}]

How can I update the value for k2 based on a condition based on the value of k1?

I would come up with this solution but it doesn't feel Pythonic. Better solutions anyone?

for item in the_list:
  if set([k1,k2]) <= item.keys():
    #cond evaluates to True or False
    if cond(item[k1]):
      item.update({k2:newvalue})

Maybe this can be done better with a map or lambda expression?

Thijs Cobben
  • 529
  • 6
  • 10
  • 2
    `<= in` is not a valid Python operator. Shouldn't that last line be indented? – Martijn Pieters Jan 04 '17 at 13:24
  • 2
    Also, you want to avoid using the variable name `dict` as that shadows the built-in. You don't need to use `dict.update()` for one key; just use `dict[k2] = newvalue` instead. – Martijn Pieters Jan 04 '17 at 13:30
  • 1
    Last but not least, your code updates the dictionaries in-place. You don't need to build a new list, you already mutated all those dictionaries that the original list is still referencing. If that's a problem, you'll need to create copies of those dictionaries first. – Martijn Pieters Jan 04 '17 at 13:31
  • What is `cond()`? What's the condition it's supposed to meet? There are also not two objects named `k1` and `k2` in your code... are they supposed to be values? – blacksite Jan 04 '17 at 13:38
  • I think the OP is trying to check whether both `k1` and `k2` belong to `dict` using [this](http://stackoverflow.com/a/1285926/4927751) – Kshitij Saraogi Jan 04 '17 at 13:45

2 Answers2

2

This is the simplest code I came up with to perform the same operation:

my_list = [{k1:v1,k2:v2}, {k1:v3, k3:v4}, {k1:v5,k2:v6},{k3:v7}]
for my_dict in my_list:
    if all (k in my_dict for k in ("k1", "k2")):
        if cond(my_dict[k1]):
            my_dict[k2] = newvalue # possibly pre-determined 

Depending on the way cond evaluates the value of k1 and/or newvalue is generated, the code might be further more "Pythonized".

Kshitij Saraogi
  • 6,821
  • 8
  • 41
  • 71
  • Thanks. I think I wrongfully was trying to update a list element by reference and then tried to update the dictionary with the update method, what was I thinking. Still I wonder if I cannot brew a map along the lines suggested in http://stackoverflow.com/questions/12229064/mapping-over-values-in-a-python-dictionary . – Thijs Cobben Jan 04 '17 at 14:03
  • @ThijsCobben Like I said, the usage of `map` and `lambda` will depend on the `cond` and `newvalue`. – Kshitij Saraogi Jan 04 '17 at 14:07
0

well in python dir(dict) shows us available methods for dictionary, and "somemethod" in dir(dict) shows us if somemethod is available in sed data type. SO if we factor it in our problem we can se that in :

py.2.7->

['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__', '__eq__',\
 '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__',\
 '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__',\
 '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__',\
 '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items', 'iteritems',\
 'iterkeys', 'itervalues','keys', 'pop', 'popitem', 'setdefault', 'update', 'values', \
'viewitems', 'viewkeys', 'viewvalues']

py.3.5 ->

['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__', '__eq__',\
 '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__',\
 '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__',\
 '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__',\
 '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items', 'iteritems',\
 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values',\
 'viewitems', 'viewkeys', 'viewvalues']

Now we can see several things here, pop,popitem,has_key,'get', and since dictionary in python is not ordered or sorted ( it prints it out as it goes ) we can also use update.

So first we need to transverse trough list of dictionaries and condition trough items, depending on size of your dictionary map or dictionary comprehension could do the trick or just dict.items() which returns list of tuples. so

def duDict(dictionary,codnitionElement,keyInQuesiton):
    el = dictionary.pop(keyInQuesiton) #similar as list.pop
    if condition(dictionary.get(codnitionElement)):
       el = something
       dictionary.update({keyInQuesiton:el })
    else:pass
    return dictionary

then something along the lines

condDict = lambda dict: duDict(dict,predefinedCondition,forKey)
map( condDict , listOfDicts )

Hope this helps

Danilo
  • 1,017
  • 13
  • 32