开发者

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 to some_list[3:8:2], giving you every second element of some_liststarting with the fourth element (which has index 3) up to the eighth element.
  • some_list[slice(2, 6)] is equivalent to some_list[2:6], giving you every element of some_liststarting with the third element (which has index 2) up to the sixth element.
  • some_list[slice(7)] is equivalent to some_list[:7], giving you every element of some_listup 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)))
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜