Помогите использовать *args в кортеже, соответствующем функции Python

Я пытаюсь создать функцию в 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) найдет совпадающие значения для значения [0] из dict1 и значения [0] из dict2. В этом случае единственным совпадением является «лягушка». Моя функция выше делает это. Что я пытаюсь сделать, так это расширить функцию, чтобы иметь возможность распечатывать другие значения из элементов словаря, где dict1[value][0] == dict2[value][0] я хочу, чтобы это было указано в аргументе функции.


person drbunsen    schedule 11.08.2011    source источник
comment
может быть, я просто глуп, но ваш вопрос кажется запутанным. значения 2 и 6 используются для item1_pos и item2_pos (args пуст) в вызове, но позже они выглядят так, как если бы они были аргументами (каким-то странным образом, который не имеет для меня смысла).   -  person andrew cooke    schedule 11.08.2011
comment
@andrewcooke извините, я вижу, что это сбивает с толку. я обновил свой вопрос, поэтому надеюсь, что теперь он понятнее.   -  person drbunsen    schedule 11.08.2011
comment
хм. это также должно быть yield(dict1[item1][item1_pos], dict2[item2][item2_pos]) в начальном блоке кода?   -  person andrew cooke    schedule 11.08.2011
comment
и даже при этом я понятия не имею, что вы подразумеваете под другими значениями каждого элемента словаря. Вы имеете в виду, что хотели бы видеть записи 1, 5 и 23 из dict1 [item1] и 3, 15 и 22 из dict2 [item2], например?   -  person andrew cooke    schedule 11.08.2011
comment
Я согласен с Андреем. Я не понимаю, какое использование вы ищете. Для чего вы ожидаете использовать *args? Можете ли вы привести пример? *args будет действовать как список аргументов в вашей функции. Я не совсем уверен, что вы собираетесь также передать вместе с этими позициями предметов? Можете ли вы также включить пример структур данных dict1 и dict2, и как бы вы хотели видеть идеальные результаты?   -  person jdi    schedule 11.08.2011


Ответы (3)


Вы сказали, что называете это как

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

Если это не то, что вы имели в виду, дайте мне знать.

person agf    schedule 11.08.2011
comment
да, спасибо за понимание моей запутанной проблемы! 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 для того, что я пытаюсь сделать? - person drbunsen; 11.08.2011
comment
Смотрите самый последний в моем ответе. Вам не нужны *args. Создайте два списка — один из элементов, которые вы хотите получить из словаря 1, другой из тех, которые вы хотите получить из словаря 2. Затем передайте эти списки. Это то, что я делаю в самом последнем примере. Он будет отлично работать для любого количества предметов, которые вы хотите от каждого из них. Видите (2, 3) и (6, 8) в последней строке кода? Это списки тех, кого вы хотите. - person agf; 11.08.2011
comment
Сначала я не понял, что ваш последний пример был именно тем, что я хотел. Серьезно, огромное спасибо за то, что остаетесь со мной так долго. Ваш ответ очень ценится. - person drbunsen; 11.08.2011

Вы можете использовать объекты срезов:

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_list, начиная с четвертого элемента (который имеет индекс 3) до восьмого элемента.
  • some_list[slice(2, 6)] эквивалентно some_list[2:6], предоставляя вам каждый элемент some_list, начиная с третьего элемента (который имеет индекс 2) до шестого элемента.
  • some_list[slice(7)] эквивалентно some_list[:7], что дает вам каждый элемент some_listдо седьмого элемента.

Если вы опустите аргументы slicer1/2, функция предполагает, что вам нужен весь список, и срезы установлены соответствующим образом.

Кроме того, я удалил ненужные поиски по словарю.

person pillmuncher    schedule 11.08.2011
comment
Я никогда раньше даже не использовал объект среза. Это интересно. Я на самом деле поражен, что вы поняли его вопрос. Думаю, теперь я тоже это понимаю, прочитав твой ответ, лол. - person jdi; 11.08.2011

Вы хотите указать произвольное количество пар индексов, чтобы попытаться сравнить совпадения?

Что-то вроде этого?

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

Я не думаю, что это ужасно полезно, но это сработает. Это все равно будет работать, если вы укажете нечетное количество аргументов из-за магии нарезки. Однако из-за этого интерфейс вашей функции сопоставления будет легко использовать неправильно.

Я бы настоятельно рассмотрел что-то вроде:

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)))
person stderr    schedule 11.08.2011