【问题标题】:Help using *args in tuple matching Python function帮助在元组匹配 Python 函数中使用 *args
【发布时间】:2011-10-24 14:02:04
【问题描述】:

我正在尝试在 python 中构建一个函数,如果来自dict1 的特定值与dict2 的特定值匹配,则该函数会产生两个字典的值。我的函数如下所示:

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])

我正在像这样使用dict_matcher

matches = [myresults for myresults in dict_matcher(dict1, dict2 , 2, 6)]
print(matches)

当我打印 matches 时,我得到一个正确匹配的 dict1 和 dict2 值列表,如下所示:

[('frog', 'frog'), ('spider', 'spider'), ('cricket', 'cricket'), ('hampster', 'hampster')]

如何向此函数添加变量参数,以便除了打印每个字典中的匹配值之外,我还可以在 dict1[item1][2] and dict2[item2][6] 匹配的情况下打印每个字典项的其他值?我可以使用 *args 吗?感谢您的帮助。

编辑: 好的,我想做什么似乎有些混乱,所以让我试试另一个例子。

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) 将从 dict1 中找到 value[0] 和 dict2 中的 value[0] 的匹配值。在这种情况下,唯一的匹配是'frog'。我上面的功能就是这样做的。我想要做的是扩展函数以便能够从字典项中打印出其他值 dict1[value][0] == dict2[value][0] 我希望在函数参数中指定它。

【问题讨论】:

  • 也许我只是愚蠢,但你的问题似乎很困惑。值 2 和 6 用于调用中的 item1_pos 和 item2_pos(args 为空),但它们稍后看起来好像是 args(以某种奇怪的方式,对我来说毫无意义)。
  • @andrewcooke 抱歉,我发现这很混乱。我更新了我的问题,所以我希望现在更清楚了。
  • 嗯。初始代码块中也应该是yield(dict1[item1][item1_pos], dict2[item2][item2_pos])吗?
  • 即使这样我也不知道你所说的“每个字典项的其他值”是什么意思。例如,您的意思是要查看 dict1[item1] 中的条目 1、5 和 23 以及 dict2[item2] 中的条目 3、15 和 22?
  • 我同意安德鲁的观点。我不明白你正在寻找的用法。您希望使用 *args 做什么?能给我举个例子吗? *args 就像函数中的参数列表一样。我不完全确定您还打算传递什么以及这些项目位置?您能否还包括 dict1 和 dict2 数据结构的示例,以及您希望如何看到理想的结果?

标签: python dictionary python-3.x match args


【解决方案1】:

你说你把它称为

matches = [myresults for myresults in dict_matcher(dict1, dict2 , 2, 6)]

你应该把它称为

matches = list(dict_matcher(dict1, dict2 , 2, 6))

它的签名是

def dict_matcher(dict1, dict2, item1_pos, item2_pos, *args):

因此传递了 4 个参数和 4 个命名参数。所以*args 的结果是args = None

我不确定你到底想要什么,但如果你这样做

yield dict1[item1][item1_pos], dict2[item2][item2_pos]

你会得到和你做的一样的东西

yield dict1[item1][2], dict2[item2][6]

如果你想得到整个匹配的项目,做

yield dict1[item1], dict2[item2]

如果你想从每个中获取一个项目,而不是匹配的项目,请执行

def dict_matcher(dict1, dict2, item1_pos, item2_pos, other1_pos, other2_pos):

yield dict1[item1][other1_pos], dict2[item2][other2_pos]

matches = list(dict_matcher(dict1, dict2 , 2, 6, 3, 8)) 

或其他任何东西,而不是 3 和 8。

如果你想得到几个,但不是所有的项目,做

def dict_matcher(dict1, dict2, item1_pos, item2_pos, other1_poss, other2_poss):

yield [dict1[item1][i] for i in other1_poss], [dict2[item2][i] for i in other2_poss]

matches = list(dict_matcher(dict1, dict2 , 2, 6, (2, 3), (6, 8))) 

或者任何代替 [2, 3] 和 [3, 8] 的东西。

如果这不是你的意思,请告诉我。

【讨论】:

  • 是的,感谢您理解我令人困惑的问题! def dict_matcher(dict1, dict2, item1_pos, item2_pos, other1_pos, other2_pos) 正是我想要的,但是我尝试使用 *args 以便每次调用该函数时都可以指定一组不同的 other1_pos 和 other2_pos 值。有时我需要这样的值:other1_pos1、other1_pos2、other2_pos3。其他时候我需要这样的值:other1_pos3、other1_pos1、other2_pos6。 *args 可以用于我想做的事情吗?
  • 查看我回答中的最后一个。你不需要 *args。制作两个列表——其中一个是您想要从 dict 1 中获得的项目,另一个是您想要从 dict 2 中获得的项目。然后传递这些列表。这就是我在最后一个例子中所做的。它适用于您想要的任意数量的项目。看到代码最后一行的(2, 3)(6, 8) 了吗?这些是您想要的列表。
  • 我最初并没有意识到你的最后一个例子正是我想要的。说真的,非常感谢你一直坚持我。非常感谢您的回答。
【解决方案2】:

你可以使用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)] 等价于some_list[3:8:2], 给你some_liststarting 的每一个第二个元素 第四个元素(索引为 3)直到第八个元素。
  • some_list[slice(2, 6)] 等价于some_list[2:6],给出 你some_list的每个元素都从第三个元素开始 (索引为 2)直到第六个元素。
  • some_list[slice(7)]相当于some_list[:7],给你 some_list 的每个元素直到第七个元素。

如果您省略 slicer1/2 参数,该函数会假定您需要整个列表并相应地设置切片。

另外,我删除了不必要的字典查找。

【讨论】:

  • 我以前从未使用过切片对象。那很有意思。我真的很惊讶你能理解他的问题。看了你的回答,我想我现在也明白了,哈哈。
【解决方案3】:

您希望指定任意数量的索引对来尝试比较匹配?

这样的?

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')]

我不认为这是非常有用的,但这样做可以。由于切片的魔力,如果您指定奇数个 args,这仍然可以工作。但是,正因为如此,匹配器函数的接口很容易被错误地使用。

我会强烈考虑类似的东西:

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)))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-12
    • 1970-01-01
    • 2016-05-08
    • 2020-03-08
    • 2013-10-26
    • 1970-01-01
    相关资源
    最近更新 更多