странное дублирование значений слияния, ключей в словаре

python #dictionary #nlp

#python #словарь #nlp

Вопрос:

Я застрял на вопросе в течение нескольких дней, любой может дать подсказку, я ценю!

Описание:

У меня есть словарь, но я хочу объединить некоторые его значения и ключи, например:

 Input:
initial_dict = {'aa': ['AA'],'bb':['BB'],'BB':['MM'],'cc':['dd'],'dd':['GG','HH','LL']}

Desired output:
goal_dict = {'aa': ['AA'],'bb':['BB','MM'],'cc':['dd','GG','HH','LL']}
 

Это означает, что если ключ / значение было в его предыдущих ключах или значениях, затем присоедините его значение / ключ к предыдущему значению, если этого значения / ключа там еще не было (возможно, не так ясно, но см. Приведенные Выше Ввод и вывод).

У меня есть следующий код, я думаю, что они идеальны, но я получил много дублирующих выходных данных:

 dict_head_conj_pair = {'aa': ['AA'],'bb':['BB'],'BB':['MM'],'cc':['dd'],'dd':['GG','HH','LL']}
dict_head_conj_new = {}
print(dict_head_conj_pair)
for a_key in dict_head_conj_pair.keys():
    if dict_head_conj_new:
        if a_key not in dict_head_conj_new.keys():
            for idx_value, new_value_list in enumerate(dict_head_conj_new.copy().values()):
                if a_key in new_value_list:
                    for idx_key, new_key in enumerate(dict_head_conj_new.copy().keys()):
                        if idx_key == idx_value:
                            target_key = new_key
                            for con_0 in range(len(dict_head_conj_pair[a_key])):
                                for new_value_list_1 in dict_head_conj_new.copy().values():
                                    dict_head_conj_new[target_key].append(dict_head_conj_pair[a_key][con_0])
                else:
                    for con_1 in range(len(dict_head_conj_pair[a_key])):
                        if con_1 == 0:
                            dict_head_conj_new.setdefault(a_key, []).append(dict_head_conj_pair[a_key][con_1])
                        else:
                            dict_head_conj_new[a_key].append(dict_head_conj_pair[a_key][con_1])
    else:
        for con_2 in range(len(dict_head_conj_pair[a_key])):
            if con_2==0:
                dict_head_conj_new.setdefault(a_key, []).append(dict_head_conj_pair[a_key][con_2])
            else:
                dict_head_conj_new[a_key].append(dict_head_conj_pair[a_key][con_2])
print("dict_head_conj_new: ",dict_head_conj_new)
 

Текущий нежелательный вывод:

 dict_head_conj_new:  {'aa': ['AA'], 'bb': ['BB', 'MM', 'MM', 'MM'], 'BB': ['MM'], 'cc': ['dd', 'dd', 'dd', 'GG', 'GG', 'GG', 'GG', 'GG', 'HH', 'HH', 'HH', 'HH', 'HH', 'LL', 'LL', 'LL', 'LL', 'LL'], 'dd': ['GG', 'HH', 'LL', 'GG', 'HH', 'LL', 'GG', 'HH', 'LL']}

 

Если кто-нибудь может увидеть, где я ошибаюсь, или дать подсказку о том, как получить желаемый результат, я очень признателен!

Спасибо!

Ответ №1:

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

 initial_dict = {'aa': ['AA'],'bb':['BB'],'BB':['MM'],'cc':['dd'],'dd':['GG','HH','LL']}
goal_dict = dict()

def find_value(val):
    for k, v in goal_dict.items():
        if val in v:
            return k

for k, v in initial_dict.items():
    if (_k := find_value(k)):
        goal_dict[_k]  = v
    elif not k in goal_dict:
        goal_dict[k] = v
 

Комментарии:

1. Спасибо! Это хорошо работает, еще один вопрос, что означает это «_k := find_value (k)»? _k не был показан ранее, но почему вы можете использовать его непосредственно как условие оценки равенства? Спасибо!

2. Это не проверка на равенство. Это так называемый «оператор моржа», который доступен в Python 3.8

Ответ №2:

 some_list = [1, 1, 1, 2, 3]
some_list = list(dict.fromkeys(some_list))
 

Вы можете запустить отладчик, чтобы найти причину проблемы (что может быть хорошо), но если вам просто нужно удалить дубликаты, то приведенный выше код может сработать. (Для удаления дубликатов из списка).

Кроме того, у меня такое чувство, что здесь могут быть уместны алгоритмы теории графов… (Например, в словаре посмотрите, можете ли вы получить доступ к элементу с помощью ключа, и если можете, вы можете сортировать «паук в» дереве)

Комментарии:

1. большое спасибо! Я вижу, что функция fromkeys() очень удобна. Кстати, знаете ли вы кого-нибудь еще, например, fromkeys(), который может удалить «ключ», который уже был в других «значениях»? Спасибо! Если нет, я напишу его сам 🙂

2. Я не думаю, что существует конкретный метод, который делает это, поскольку это звучит ужасно специфично: (Я бы сказал, что вам нужно будет написать это самостоятельно… (Кроме того, если у меня будет время, я мог бы попытаться написать сценарий, который вы пытались выполнить, используя алгоритм graph, если у меня будет время :))

Ответ №3:

Если я правильно понял, вы можете смоделировать это как проблему с графом, поэтому я предлагаю вам использовать networkx:

 import operator

import networkx as nx

initial_dict = {'aa': ['AA'], 'bb': ['BB'], 'BB': ['MM'], 'cc': ['dd'], 'dd': ['GG', 'HH', 'LL']}
dg = nx.convert.from_dict_of_lists(initial_dict, create_using=nx.DiGraph)

# these are the keys of the dictionaries
seeds = [n for n in dg.nodes if not dg.in_degree(n)]


def descendants(g, source):
    """This function finds all the descendants of source in g sorted by distance to source"""
    desc = sorted(nx.shortest_path_length(g, source).items(), key=operator.itemgetter(1))
    return [d for d, _ in desc if d != source]


# return as dictionary
res = {seed: descendants(dg, seed) for seed in seeds}
print(res)
 

Вывод

    {'aa': ['AA'], 'bb': ['BB', 'MM'], 'cc': ['dd', 'HH', 'GG', 'LL']}