Help using *args in tuple matching Python function
I am trying to build a function in python that yields values of two dictionaries IF a particular value from dict1
matches a particular value of dict2
. My function looks like this:
def dict_matcher(dict1, dict2, item1_pos, item2_pos):
"""Uses a tuple value from dict1 to search for a matching tuple value in dict2. If a match is found, the other values from dict1 and dict2 are returned."""
for item1 in dict1:
for item2 in dict2:
if dict1[item1][item1_pos] == dict2[item2][item2_pos]:
yield(dict1[item1][2], dict2[item2][6])
I am using dict_matcher
like this:
matches = [myresults for myresults in dict_matcher(dict1, dict2 , 2, 6)]
print(matches)
When I print matches
I get a list of correctly matching dict1 and dict2 values like this:
[('frog', 'frog'), ('spider', 'spider'), ('cricket', 'cricket'), ('hampster', 'hampster')]
How can I add variable arguments to this function so that, in addition to printing the matching values from each dictionary, I can also print the other values of each dictionary item in instances where dict1[item1][2] and dict2[item2][6]
match? Can I use *args? Thanks for the help.
EDIT: Ok, there seems to be some confusion as to what I am trying to do so let me try another example.
dict1 = {1: ('frog', 'green'), 2: ('spider', 'blue'), 开发者_运维百科3: ('cricket', 'red')}
dict2 = {a: ('frog', 12.34), b: ('ape', 22.33), c: ('lemur', 90.21)}
dict_matcher(dict1, dict2, 0, 0)
would find matching values for value[0] from dict1 and value[0] from dict2. In this case, the only match is 'frog'. My function above does this. What I am trying to do is extend the function to be able to print out other values from the dictionary items where dict1[value][0] == dict2[value][0]
I want this to be specified in the function argument.
You could use slice objects:
def dict_matcher(dict1, dict2, pos1, pos2, slicer1=(), slicer2=()):
slice1 = slice(*slicer1) if slicer1 else slice(len(dict1))
slice2 = slice(*slicer2) if slicer2 else slice(len(dict2))
for data1 in dict1.values():
for data2 in dict2.values():
if data1[pos1] == data2[pos2]:
yield data1[slice1], data2[slice2]
for result1, result2 in dict_matcher(my_dict, your_dict, 2, 6, (3, 8, 2), (2, 6)):
print result1, result2
some_list[slice(3, 8, 2)]
is equivalent tosome_list[3:8:2]
, giving you every second element ofsome_list
starting with the fourth element (which has index 3) up to the eighth element.some_list[slice(2, 6)]
is equivalent tosome_list[2:6]
, giving you every element ofsome_list
starting with the third element (which has index 2) up to the sixth element.some_list[slice(7)]
is equivalent tosome_list[:7]
, giving you every element ofsome_list
up to the seventh element.
If you omit the slicer1/2
arguments, the function assumes you want the whole list and the slices are set accordingly.
Also, I removed unnecessary dictionary lookups.
You said you're calling it as
matches = [myresults for myresults in dict_matcher(dict1, dict2 , 2, 6)]
You should be calling it as
matches = list(dict_matcher(dict1, dict2 , 2, 6))
and it's signature is
def dict_matcher(dict1, dict2, item1_pos, item2_pos, *args):
So 4 arguments passed, and 4 named arguments. So *args
results in args = None
.
I'm not sure exactly what you want, but if you do
yield dict1[item1][item1_pos], dict2[item2][item2_pos]
You'll get the same thing as you get from doing
yield dict1[item1][2], dict2[item2][6]
If you want to get the whole matching items, do
yield dict1[item1], dict2[item2]
If you want to get one item from each, but not the matching item, do
def dict_matcher(dict1, dict2, item1_pos, item2_pos, other1_pos, other2_pos):
and
yield dict1[item1][other1_pos], dict2[item2][other2_pos]
and
matches = list(dict_matcher(dict1, dict2 , 2, 6, 3, 8))
or whatever instead of 3 and 8.
If you want to get several, but not all items, do
def dict_matcher(dict1, dict2, item1_pos, item2_pos, other1_poss, other2_poss):
and
yield [dict1[item1][i] for i in other1_poss], [dict2[item2][i] for i in other2_poss]
and
matches = list(dict_matcher(dict1, dict2 , 2, 6, (2, 3), (6, 8)))
or whatever instead of [2, 3] and [3, 8].
If this isn't what you meant, let me know.
You're looking to specify an arbitrary number of pairs of indexes to try to compare for matches?
Something like this?
def matcher(d1, d2, *args):
indexes = zip(args[0::2], args[1::2])
for a, b in indexes:
for value1 in dict1.values():
for value2 in dict2.values():
x, y = value1[a], value2[b]
if x == y:
yield x, y
dict1 = {1: ('frog', 'green'), 2: ('spider', 'blue'), 3: ('cricket', 'red')}
dict2 = {a: ('frog', 12.34), b: ('ape', 22.33), c: ('lemur', 90.21)}
matches = list(matcher(d1, d2,
0, 0, # first pair to search for matches
1, 1 # second pair,
# ... and so on,
))
print matches
# [('frog', 'frog')]
I don't think this is terribly usable but this would do it. This will still sort of work if you specify odd numbers of args due to the magic of slicing. However, because of this the interface to your matcher function is going to be easy to use incorrectly.
I'd strongly consider something more like:
def matcher(d1, d2, indexes_to_check):
...
print list(matcher(d1, d2, [(0, 0), (1, 1), ...]))
def matcher(d1, d2, *indexes_to_check):
...
print list(matcher(d1, d2, (0, 0), (1, 1)))
精彩评论