Nested dictionaries filtering

python

#1

Hi all, I am trying to create a mini tagging for my widgets in which it will sets the visibility display accordingly to a list of checkboxes states.

For each of my checkboxes, it was initiallly returning a dictionary whenever it was toggled and my widgets are a list of nested dictionaries.

Currently I had the problem where my widgets will be set to hidden even if its other checkboxes are still True.

nested = {
    'item01' : {
        'k1' : ['1a', '1c'],
        'k2' : ['2b']
        },
    'item02' : {
        'k1' : ['1b', '1c'],
        'k2' : ['2b', '2c'],
        'k3' : ['3a']
        },
    'item03' : {
        'k1' : ['1c'],
        'k3' : ['3a', '3c']
        }
}

# chk derives from user selections in which it is always changing
chk = {'k1' : '1c', 'k3' : '3c'}
ck = chk.keys()
cv = chk.values()



for nk, nv in nested.items ():
    if nv.has_key(ck) and [i for i in nv[ck] if i == cv]:
        print '{0} will be shown'.format(nk)
    
    else:
        print '>>> no matching keys/ values'
        print '{0} will be hidden'.format(nk)

For example, ‘chk’ which is the checked options, while it will shown item01 and item03, and say if I checked off where ‘k1:1c’, item03 will be hidden despite ‘k3:3c’ option is still checked.

Any insights on how I can made this better?

Apologise in advance for the vague example…


#2

No worries about being vague. Abstract ideas can be difficult to get across.

Anyway, your nested dictionary structure will work just fine, but your loop that decides which items to show is the problem. You should check each checkbox against each item one-at-a-time (instead of all checkboxes at once like you are currently trying). So, what you need are two nested loops. One that iterates over nested, and one that iterates over the chk dictionary.

Now for the if statement. Use ck in nv instead of nv.has_key(ck). It’s more pythonic, and has_key is being removed in the future. Also, your list comprehension can be updated similarly with cv in nv[ck]. This makes things much more readable.

As you’re looping over all those possibilities, you should just be looking for the items that work, and ignoring the ones that don’t. If you find an item that doesn’t match the current checkbox, it may work on the next one. So instead of printing what will be shown/hidden inside the loop, we’ll make a set() (so we don’t get duplicate items like we would in a list) and keep track of the items that should be shown.

Then after all that, we have a set() containing all the items we want to show.

Or, in code form, re-using the nested dict from above:

chk = {'k1' : '1c', 'k3' : '3c'}

shown = set()
for item, nv in nested.items():
    for ck, cv in chk.items():
        if ck in nv and cv in nv[ck]:
            shown.add(item)

print "These items will be shown:", shown

– Edited for clarity


#3

Thanks for getting back.

It appears that I have missed out a variable (my bad, sorry) in which I still have a toggled flag (True/ False from the checkbox state)

Reason being, while your code somewhat works in my favour, but it is not hiding some of the widgets though even when I tried to draft up another variable called not_shown, adding it after the if loop of if ck in nv and cv in nv[ck]:


#4

Roughing it here, but couldn’t something like set comprehension handle this and just casting indices as bools:


widgets = {
  "tab_x":["widget_a", "widget_b", "widget_c"],
  "tab_y":["widget_d", "widget_e", "widget_f"],
  "tab_z":["widget_g", "widget_h", "widget_i"]
}

selection = {
  "tab_x": ["widget_a"], 
  "tab_z": ["widget_h", "widget_i"]}

for key, value in selection.items():

  if key in widgets:

    enabled = list(set(value) & set(widgets[key]))
    disabled = list(set(value) ^ set(widgets[key]))

    for i, j in enumerate([disabled, enabled]):

      for k in j:
        print "Set {0} visible to {1}".format(k, bool(i))

# >>>
# Set widget_c visible to False
# Set widget_b visible to False
# Set widget_a visible to True
# Set widget_g visible to False
# Set widget_i visible to True
# Set widget_h visible to True


#5

Could you post an update with the correct data?


#6

How many checkboxes do you need to set per item?

Edit: more to the point; is this to filter a table or item list based off criteria/settings?


#7

could you just key the info you need to a full path for the widgets so that the dictionary is flatter?

{
    'tab_x/widget_a': True,
   'tab_x/widget_b': False
}

etc?