Python字典中的反向键(由列表组成)和值

Python字典中的反向键(由列表组成)和值,python,dictionary,list-comprehension,state-machine,Python,Dictionary,List Comprehension,State Machine,我一直试图从这里的其他帖子中找出这个问题,但是没有 我有一本Python字典 old_dict = { (1,'a') : [2], (2,'b') : [3,4], (3,'x') : [5], (4,'y') : [5], (5,'b') : [3,4], (5,'c') : [6], } 我需要扭转这一点,因此我将: new_dict = { (6,'c') : [5

我一直试图从这里的其他帖子中找出这个问题,但是没有

我有一本Python字典

old_dict = { (1,'a') : [2],
          (2,'b') : [3,4],
          (3,'x') : [5],
          (4,'y') : [5],
          (5,'b') : [3,4], 
          (5,'c') : [6],
          }
我需要扭转这一点,因此我将:

new_dict = { (6,'c') : [5],
          (5,'x') : [3],
          (5,'y') : [4],
          (4,'b') : [5, 2],
          (3,'b') : [5, 2], 
          (2,'a') : [1],
          }
(这描述了有限状态机的边缘,我需要向后运行它:它必须像以前一样接受反向输入)

例如,在旧字典中,第一个键是一个列表
(1,'a'):[2]
,现在,这个键应该变成
(2,'a'),[1]
。。。或者
(4,'y'):[5]
变成
(5,'y'):[4]
等等-我希望我的意思可以理解

我一直试图用列表的理解来解决这个问题,但还没有成功

更新:我尝试了他的建议,但不知何故,我无法让代码正常工作。我将其插入到函数中,如下所示:

old_dict1 = { (1,'a') : [2],
          (2,'b') : [3,4],
          (3,'x') : [5],
          (4,'y') : [5],
          (5,'b') : [3,4], 
          (5,'c') : [6],
          }

def reverse_dict(old_dict):
    new_dict = {}
    add_to_dict = new_dict.setdefault

    map(lambda kv: add_to_dict(kv[0], []).append(kv[1]),   
        sum([[((x, k[1]), k[0]) for x in v] for k, v in old_dict.items()],
            []))        # sum will take this to start adding
    return new_dict

new_dict1 = reverse_dict(old_dict1)

print(new_dict1)
但是我只得到一个空字典
{}


我做错什么了吗?(我实际上对Python知之甚少,因此如果我犯了一个太愚蠢的错误,请原谅我…

这足够复杂,我不必费心理解列表。另外,我假设您不希望值列表有任何严格的顺序

new_dict = {}
for k, vals in old_dict.items():
    k_num, k_char = k
    for num in vals:
        new_dict.setdefault((num, k_char), []).append(k_num)
或者使用
defaultdict

new_dict = collections.defaultdict(list)
for k, vals in old_dict.items():
    k_num, k_char = k
    for num in vals:
        new_dict[(num, k_char)].append(k_num)
对于那些对尽可能简洁感兴趣的人来说,我觉得这个更压缩的版本也是一个选择。从可读性的角度来看,我不确定自己对此有何感想,因此为了更清楚一点,我更改了变量名:

new_dict = collections.defaultdict(list)
for (num_in, char_in), nums_out in old_dict.items():
    for num_out in nums_out:
        new_dict[(num_out, char_in)].append(num_in)

这适用于你的数据,只是为了好玩,把它当作一个丑陋的黑客

最好用更多的代码行来编写,这样更容易理解,但有时我还是忍不住要编写这个装置

希望能有帮助

def reverse_dict(old_dict):
    """
    >>> sorted(reverse_dict({(1,'a'): [2],
    ...               (2,'b'): [3,4],
    ...               (3,'x'): [5],
    ...               (4,'y'): [5],
    ...               (5,'b'): [3,4], 
    ...               (5,'c'): [6],
    ...              }).items())
    [((2, 'a'), [1]), ((3, 'b'), [2, 5]), ((4, 'b'), [2, 5]), ((5, 'x'), [3]), ((5, 'y'), [4]), ((6, 'c'), [5])]
    """
    new_dict = {}
    add_to_dict = new_dict.setdefault       # you could use a [defaultdict][1] instead

    map(lambda kv: add_to_dict(kv[0], []).append(kv[1]),   # if kv[0] not in dict get [] and add to it
        sum([[((x, k[1]), k[0]) for x in v] for k, v in old_dict.items()],
            []))        # sum will take this to start adding
    return new_dict
要测试代码,只需将其复制到一个文件
so.py
,并按如下方式运行:

$ python -m doctest so.py -v
Trying:
    sorted(reverse_dict({(1,'a'): [2],
                  (2,'b'): [3,4],
                  (3,'x'): [5],
                  (4,'y'): [5],
                  (5,'b'): [3,4], 
                  (5,'c'): [6],
                 }).items())
Expecting:
    [((2, 'a'), [1]), ((3, 'b'), [2, 5]), ((4, 'b'), [2, 5]), ((5, 'x'), [3]), ((5, 'y'), [4]), ((6, 'c'), [5])]
ok
1 items had no tests:
    so
1 items passed all tests:
   1 tests in so.reverse_dict
1 tests in 2 items.
1 passed and 0 failed.
Test passed.

它用来使测试它是否做了你想做的事情变得更容易。

我认为你对
口述的目的理解有问题。
dict
数据结构不应被认为是以任何特定方式排序的,因为它使用哈希表来访问元素。您应该阅读,并且
中关于实现细节的说明。items()
也很重要。事实证明,实现可能会给您看起来期望的顺序,但您不应该指望它


如果订单对您很重要,那么您应该至少在代码中订单重要的部分使用
列表
。使用
dict
上的
.items()
方法获取
(键、值)
对的列表,然后可以使用列表上的常用排序方法对它们进行任意排序

我建议使用
items()
而不是
iteritems()
,因为它适用于Python2.x和3.x,并且OP的问题似乎不会因为获得一个完全格式的列表而受到不利影响(在Python2.x的情况下)。一般来说,我认为我们应该推荐Python3语法,只要它在Python2中也可以使用,并且没有指定版本。@JohnY,我认为这是一个非常好的观点。但另一方面,我也有不少评论员抱怨我过去没有使用
iteritems
。我习惯于更多地使用
iteritems
来表示我意识到了手头的问题,我认为我的读者也是。然后,如果出现这种情况,我可以随时补充必要的注意事项。另外——如果在Python 2中浪费地使用
项,您不会得到任何警告,但是在Python 3中,如果您尝试使用
iteritems
,您会立即意识到有问题。所以我现在倾向于使用
iteritems
。嗨,森德尔和约翰尼,谢谢。。。老实说,这两个我都不知道,但无论如何,我是否必须导入一些库才能工作?我收到一个错误“dict”对象没有属性“iteritems”我做错了什么?@Jens按照johny的建议使用
items()
而不是
iteritems()
@senderle:我过去在展示非惰性版本时也会遇到静态问题。你不会赢的嗨,F.C.谢谢你。不知何故,我无法使它工作。。。如果代码如下所示:old_dict1={(1,'a'):[2],(2,'b'):[3,4],(3,'x'):[5],(5,'b'):[3,4],(5,'c'):[6],}def reverse_dict(old_dict):new_dict={}add to_dict=new_dict.setdefault,您可以使用[defaultdict][1]映射(lambda kv:将_添加到_dict(kv[0],])。附加(kv[1]),如果kv[0]不在dict中,则获取[],并将其相加([[((x,k[1]),k[0]),对于x in v,对于k,v在旧_dict.items(),[]))#sum将以此开始添加return new_dictHi,我只知道很少的Python,事实上……但是字典是一个键值对,我基本上想让键成为值,值成为键(其中键是元组,值是一个或多个项的列表),根本不关心钥匙的顺序。很抱歉我的误解。当我读到你想要的东西时,我一定是在读的时候很匆忙。我处理了你在你的问题中发布的答案中的信息。如果你认为它不再相关,请随时删除它。@senderle谢谢…我仍然不知道他的一个工作,仍然只得到一个空字典返回。但无论如何,你的另一个职位已经为我工作得很好了!