Compare dictionary key, values with nested list elements - Python

3.9k Views Asked by At

Trying to match key, values in dictionaries with nested list elements

dict = {'a':[1, 5], 'c':[7, 9], 'f':[10, 12], 'b':[15, 20]}
list_A = [['a', '4'], ['a', '7'], ['b', '17'], ['b', 10], ['c', '7'], ['d', '7'], ['f', '11'], ['f', '12']]
list_A_no_reps =['a', 'b', 'c', 'd', 'f']

I am trying to get a list which has the values that match with list_A and dict i.e. as in the values of list a ( the second elements in the nested lists) should lie between the value list pair of the dict.

match_list = [['a', '4'], ['b', '17'], ['c', '7'], ['f', '11'], ['f', '12']]

I am trying to first match the keys of dict with list_A_no_reps and if there is a match, I am trying to find out if it lies between the values of each key, value pair. I have this so far:

g = []
for key, values in dict.items():
   for element in list_A_no_rep:
      if key == element:
         for cord in list_A:
            if (values[0] <= int(cord[1]) <= values[2]):
               g.append(cord)
4

There are 4 best solutions below

0
On BEST ANSWER

I would group the sublists in a dict by the first element which is the letter then iterate over your original dict and check if each key is in the grouping dict and do your comparison.

d = {'a': [1, 5], 'c': [7, 9], 'f': [10, 12], 'b': [15, 20]}

list_A = [['a', '4'], ['a', '7'], ['b', '17'], ['b', 10], ['c', '7'], ['d', '7'], ['f', '11'], ['f', '12']]

from collections import defaultdict

d2 = defaultdict(list)

for k,v in list_A:
    d2[k].append(v)

out = []
for k, v in d.items():
    if k in d2:
        vals = d2[k]
        for v2 in vals:
            if v[0] <= int(v2) <= v[1]:
                out.append([k,v2])
print(out)
['a', '4'], ['c', '7'], ['b', '17'], ['f', '11'], ['f', '12']]

Or use viewkeys to get the common keys:

out = []
for k in d.viewkeys() & d2.viewkeys():
    vals, v = d2[k], d[k]
    for v2 in vals:
        if v[0] <= int(v2) <= v[1]:
            out.append([k,v2])

Or just loop over listA:

d = {'a': [1, 5], 'c': [7, 9], 'f': [10, 12], 'b': [15, 20]}

list_A = [['a', '4'], ['a', '7'], ['b', '17'], ['b', 10], ['c', '7'], ['d', '7'], ['f', '11'], ['f', '12']]

out = []
for sub in list_A:
    k, val = sub
    if k in d:
        v = d[k]
        if v[0] <= int(val) <= v[1]:
            out.append(sub)
print(out)
[['a', '4'], ['b', '17'], ['c', '7'], ['f', '11'], ['f', '12']]
0
On

Update

Change values[2] to values[1]

As your dictionary has two elements and indexing is zero based, so [1, 5] would result in values[0] == 1 and values[1] == 5

Also you might like to go for a better solution, by leaving out list_A_no_reps and removing the if key == element block, then using cord[0] to compare.

0
On

You can try:

g = []
for key, values in dict.items():
    if key in list_A_no_rep:
        for cord in list_A:
        if ( cord[0] == key ):
                if (values[0] <= int(cord[1]) <= values[1]):
                    g.append(cord)
print g

Output:

[['a', '4'], ['c', '7'], ['b', '17'], ['f', '11'], ['f', '12']]

Modification in your code:

g = []
for key, values in dict.items():
    for element in list_A_no_rep:
        if key == element:
            for cord in list_A:
                if ( cord[0] == element ): #line added
                    if (values[0] <= int(cord[1]) <= values[1]):
                        g.append(cord)

The problem in your code was that you were checking with all other elements of list_A too. Therefore you would be getting the undesired value which might come within the range of some another key's range. So a if condition is required to check if a valid comparison with same key is occurring.

For example, without if condition you would have checked ['a','7'] with c:[7,9]. Hence you would have included it in g even though it does not satisfy the range specified for a.

0
On
d = {'a':[1, 5], 'c':[7, 9], 'f':[10, 12], 'b':[15, 20]}
li = [['a', '4'], ['a', '7'], ['b', '17'], ['b', 10], ['c', '7'], ['d', '7'], ['f', '11'], ['f', '12']]

It would be quicker to look up a key in d for each set of values in li than iterate through the list for each key in d. This can be done in a single line with a list comprehension:

match_li = [v for v in li if v[0] in d and  d[v[0]][0] <= int(v[1]) <=  d[v[0]][2]]

yields

[['a', '4'], ['b', '17'], ['c', '7'], ['f', '11'], ['f', '12']]