3

I have a data structure L = [(int, dict{key: values}), (int,dict{key: values})...].

Given an input list [0,1] I want to find any dictionary key where both/all values of the input list [0,1] exist.

Currently, my bug is that if I use input_list = [0,1], the function will return a match where the dictionary values are just [0] and where values are [0,1]. Only this second result is desirable. I feel like this is a minute change, but I can't grasp it. What do I change to make this happen?

Code

#Python3
L = [(0, {0: [0], 1: [0, 1], 2: [0, 2], 3: [0, 3], 4: [0, 4]}), (1, {0: [1, 0], 1: [1], 2: [5, 1, 2,], 3: [1, 3], 4: [1, 4]}), (2, {0: [2, 0], 1: [2, 1], 2: [2], 3: [2, 3], 4: [2, 4]}), (3, {0: [3, 0], 1: [3, 1], 2: [3, 2], 3: [3], 4: [3, 4]}), (4, {0: [4, 0], 1: [4, 1], 2: [4, 2], 3: [4, 3], 4: [4]})]

#input_list = (eval(input('Enter your list: ')))
#input_list = ([0,1])
print('Input: ' + str(input_list))
for tupl in L:
    dict_a = (tupl[1])
    matching_key = ([key for key, value in dict_a.items() if all(v in input_list for v in value)])
    print('Node: ' + str(tupl[0]) + ' Match at key(s): ' + str(matching_key))

Output

L = [(0, {0: [0], 1: [0, 1], 2: [0, 2], 3: [0, 3], 4: [0, 4]}), (1, {0: [1, 0], 1: [1], 2: [5, 1, 2,], 3: [1, 3], 4: [1, 4]}), (2, {0: [2, 0], 1: [2, 1], 2: [2], 3: [2, 3], 4: [2, 4]}), (3, {0: [3, 0], 1: [3, 1], 2: [3, 2], 3: [3], 4: [3, 4]}), (4, {0: [4, 0], 1: [4, 1], 2: [4, 2], 3: [4, 3], 4: [4]})]

Enter your list: [0,1]
Input: [0, 1]
Node: 0 Match at key(s): [0, 1]
Node: 1 Match at key(s): [0, 1]
Node: 2 Match at key(s): []
Node: 3 Match at key(s): []
Node: 4 Match at key(s): []

Enter your list: [1,5,2]
Input: [1, 5, 2]
Node: 0 Match at key(s): []
Node: 1 Match at key(s): [1, 2]
Node: 2 Match at key(s): [1, 2]
Node: 3 Match at key(s): []
Node: 4 Match at key(s): []

Thank you:)

Sharad S.
  • 75
  • 1
  • 6
  • Do you actually want ```input_list == value```? Or if ```value``` contains all items in ```input_list```? – wwii Nov 22 '16 at 03:19

3 Answers3

2

You have the code checking if value contains all the items in input_list the wrong way around. all(v in input_list for v in value) checks that all the items in value can be found from input_list. If you change it the other way around it will work as you expected:

all(v in value for v in input_list)

Note that if you would convert input_list to set you could easily check if input_list is a subset of value. That would be easier to understand and more efficient:

L = [(0, {0: [0], 1: [0, 1], 2: [0, 2], 3: [0, 3], 4: [0, 4]}), (1, {0: [1, 0], 1: [1], 2: [5, 1, 2,], 3: [1, 3], 4: [1, 4]}), (2, {0: [2, 0], 1: [2, 1], 2: [2], 3: [2, 3], 4: [2, 4]}), (3, {0: [3, 0], 1: [3, 1], 2: [3, 2], 3: [3], 4: [3, 4]}), (4, {0: [4, 0], 1: [4, 1], 2: [4, 2], 3: [4, 3], 4: [4]})]

input_list = set([0,1])

for tupl in L:
    dict_a = tupl[1]
    matching_key = [key for key, value in dict_a.items() if input_list <= set(value)]
    print('Node: ' + str(tupl[0]) + ' Match at key(s): ' + str(matching_key))

Output:

Node: 0 Match at key(s): [1]
Node: 1 Match at key(s): [0]
Node: 2 Match at key(s): []
Node: 3 Match at key(s): []
Node: 4 Match at key(s): []
niemmi
  • 17,113
  • 7
  • 35
  • 42
0

You can use set subtraction to solve:

#Python3
L = [(0, {0: [0], 1: [0, 1], 2: [0, 2], 3: [0, 3], 4: [0, 4]}), (1, {0: [1, 0], 1: [1], 2: [5, 1, 2,], 3: [1, 3], 4: [1, 4]}), (2, {0: [2, 0], 1: [2, 1], 2: [2], 3: [2, 3], 4: [2, 4]}), (3, {0: [3, 0], 1: [3, 1], 2: [3, 2], 3: [3], 4: [3, 4]}), (4, {0: [4, 0], 1: [4, 1], 2: [4, 2], 3: [4, 3], 4: [4]})]

input_list = (eval(input('Enter your list: ')))
#input_list = [1,5,2]
print('Input: ' + str(input_list))
for tupl in L:
    dict_a = (tupl[1])
    matching_key = []
    for key, lst in tupl[1].items():
        if not (set(lst) - set(input_list)):
            matching_key.append(key)
    print('Node: ' + str(tupl[0]) + ' Match at key(s): ' + str(matching_key))

And I would recommend you to avoid constructions like this [key for key, value in dict_a.items() if all(v in input_list for v in value)] because it confuses, it makes your code hard to understand.

Fomalhaut
  • 8,590
  • 8
  • 51
  • 95
  • How would you edit this to improve readability, and keep it efficient? (in reference to niemmi's sollution) – Sharad S. Nov 23 '16 at 00:14
  • I think Niemmi's solution is pretty good. Sometimes it's better to avoid expressions like `[key for key, value in dict_a.items() if input_list <= set(value)]`. They are readable though but also they may confuse especially if you want to make some changes in your scipt. The other disadvantage is if you have an error in a line like `[key for key, value in dict_a.items() if input_list <= set(value)]` you don't know exactly which operation led to the exception. But if you do as I showed, the traceback will show you the exact line with the error. – Fomalhaut Nov 23 '16 at 04:26
-1

Please read:

Check if two unordered lists are equal and How can I compare two ordered lists in python?

Depending on the semantics you want to use when checking for equality you can use one solution or the other. If you are going for a simple ordered list comparison, I would go with:

for tupl in L:
    dict_a = (tupl[1])
    if dict_a != input_list:
        continue
    print('Node: ' + str(tupl[0]) + ' Match at key(s): ' + str(matching_key))
Community
  • 1
  • 1
Alexei Z
  • 79
  • 1
  • 3
  • ```dict_a``` is a dictionary, when would it be equal to a list? – wwii Nov 22 '16 at 03:28
  • oops, my bad. Then we would go back to: – Alexei Z Nov 22 '16 at 03:32
  • oops again, we would go back to: for tupl in L: dict_a = (tupl[1]) matching_key = ([key for key, value in dict_a.items() if v == iinput_list ]) print('Node: ' + str(tupl[0]) + ' Match at key(s): ' + str(matching_key)) – Alexei Z Nov 22 '16 at 03:35