如何根据值更新字典键?

How to update dictionary key based on value?

我有两本字典,它们的值相似,但键不同。我想用第一本字典 user.

的键值更新第二本字典 db

在不使逻辑过于复杂的情况下,最佳方法是什么?

例如,我有以下词典:

user = {'school': ['books', 'pencils', 'sheets', 'notebooks']}
db = {'education': ['books', 'pencils', 'sheets', 'notebooks'],
      'actors': ['student', 'teacher', 'principal']}

user['school']db['education'] 具有相同的列表值。我只想将 db 中的键值更新为 user 中的键值。我认为实现方式如下:

def get_key(my_dict, val):
    for key, value in my_dict.items():
        if val == value: 
            return key 
    return None

res = {}
for key, value in db.items():
    if value in user.values():
        key_user = get_key(user, value)
        if key_user:            
            res.update({key_user: value})
    else:
        res.update({key: value})

print(res)

我在 Python 3.6.6 中实现了这一点,据我所知,字典条目的顺序得以保留。

所需的输出如下:

{'school': ['books', 'pencils', 'sheets', 'notebooks'],
 'actors': ['student', 'teacher', 'principal']}

如果您为 user 字典创建一个 reverse-loopup dict 可能会更有效率。

逻辑减少到只有 2 行代码:

reverse_user = {tuple(user[key]):key for key in user}

new_db_dict = {reverse_user[tuple(db[db_key])]:db[db_key] for db_key in db if tuple(db[db_key]) in reverse_user}

new_db_dict_excl = {key:db[key] for key in db if tuple(db[key]) not in reverse_user}

new_db_dict.update(new_db_dict_excl)

当我们意识到我们可以用 user 更新整个 db 时,我们可以使它更简单一些。我们需要弄清楚的是在我们更新它之前要删除哪些键,同时还要注意在我们迭代它时不要修改 db

user = {'school': ['books', 'pencils', 'sheets', 'notebooks']}
db = {'education': ['books', 'pencils','sheets','notebooks'],
      'actors': ['student','teacher','principal']}

for user_value in user.values():
    for del_key in [db_key for db_key, db_value in db.items() if user_value == db_value]:
        del db[del_key]

db.update(user)

>>> {'actors': ['student', 'teacher', 'principal'],
     'school': ['books', 'pencils', 'sheets', 'notebooks']}

正如您所说,顺序很重要,我认为最简单的方法是 re-create 字典,但对于较大的数据集效率不高。

我们可以迭代db到re-create它,我们唯一需要看的是使用userdb中的密钥。如果密钥存在于 user_values 中,那么我们可以获取它的索引并使用它从 user_keys 中获取密钥,否则我们使用 key.

user = {'school': ['books', 'pencils', 'sheets', 'notebooks']}
db = {'education': ['books', 'pencils','sheets','notebooks'],
      'actors': ['student','teacher','principal']}

user_keys = tuple(user.keys())
user_values = tuple(user.values())

new_db = {user_keys[user_values.index(value)] if value in user_values else key: value for key, value in db.items()}

>>> {'school': ['books', 'pencils', 'sheets', 'notebooks'],
     'actors': ['student', 'teacher', 'principal']}

我喜欢 Serial Lazer's 有一个颠倒的 dict,但其余部分有点笨拙恕我直言。我会做一个简单的 for-loop 来代替:

x = {'a': [1, 2, 3]}  # "user"
y = {'b': [1, 2, 3], 'c': [4, 5, 6]}  # "db"

rev = {tuple(v): k for k, v in x.items()}
result = {}
for k, v in y.items():
    try:
        k = rev[tuple(v)]
    except KeyError:
        pass
    result[k] = v

print(result)  # -> {'a': [1, 2, 3], 'c': [4, 5, 6]}

或者你可以使用 ChainMap 如果你可以反转所有的命令,将它们的值转换为元组,然后返回。

from collections import ChainMap

c = ChainMap(*[{tuple(v): k for k, v in d.items()} for d in (x, y)])
result = {v: list(k) for k, v in c.items()}

或者只是一个简单的字典:

x_rev, y_rev = [{tuple(v): k for k, v in d.items()} for d in (x, y)]
y_rev.update(x_rev)
result = {v: list(k) for k, v in y_rev.items()}