有没有更符合Python风格的方法来遍历字典键以查找值?

3
下面是一个示例字典,colors:
{
    "Red" : {
        "members" : {
            "153950039532134112" : {
                "rank" : 1,
                "score" : 43,
                "time" : 1530513303
            }
        },
        "rank" : 2,
        "score" : 43
    },
    "Blue" : {
        "members" : {
            "273493248051539968" : {
                "rank" : 1,
                "score" : 849,
                "time" : 1530514923
            },
            "277645262486011904" : {
                "rank" : 2,
                "score" : 312,
                "time" : 1530513964
            },
            "281784064714487810" : {
                "rank" : 3,
                "score" : 235,
                "time" : 1530514147
            }
        },
        "rank" : 1,
        "score" : 1396
    }
}

为了举例说明,假设这个字典中有很多其他颜色命名的键。现在,假设我正在寻找一个特定的成员ID。

for key, value in colors.items():
    if member_id in value['members']:
        return True

有没有更简单的方式,可能只需要一行代码就能实现这个功能?

你期望得到一个单一的结果吗?还是一个颜色列表,其中包含成员ID? - Vincent Pakson
那么你不需要 colors[key],因为这只是 value,所以等同于 if member_id in value['members']。但这只是小事情,因为在字典中进行索引是一个 O(1) 操作。 - AChampion
4个回答

7
这里有另一个一行代码,使用与any相结合的生成器表达式:generator expression
return any(member_id in color['members'] for color in colors.values())

@skrx 我今天学到了列表推导式和生成器表达式的区别。这个链接可以帮助解释答案中的一行迭代。我并没有故意添加错误信息。考虑到获得的批准数量,我认为这是一个好的编辑。 - DoloMike

1
这是一种单行完成此操作的方法:
member_id="273493248051539968"

[k for k, v in colors.items() if member_id in v['members']]

输出:

['Blue']

1
你知道它在v['members']中,所以这似乎是不必要的复杂。假设OP不仅仅是寻找一个True/False返回值,那么[k for k, v in colors.items() if member_id in v['members']]可以达到同样的效果。 - AChampion
这将输出包含该member_id的所有键的列表。如果这正是您想要的,那么很好,但这也意味着它必须搜索整个字典而不会进行快捷方式,与问题中的长解决方案不同,这很糟糕,因为“colors”应该是一个大字典,如果每个成员ID只出现一次,则额外的工作是无用的。 - gilch

1
next((k for k, v in colors.items() if member_id in v['members']), None)

计算出具有该member_id的第一个颜色键,例如'Blue'(如果找不到则为None)。

生成器表达式是惰性的,因此一旦找到匹配项,它将停止搜索。


这是一种奇怪的表达方式,完全不符合Python的风格。它也不比使用生成器的any函数更有效,而后者已经是一个现成的解决方案了。 - Matthew Story
@MatthewStory 不会的,你可以试试。next 函数接受一个额外的默认参数,可以抑制 StopIteration 行为。与 any 不同,它可以找到第一个键。 - gilch
哦,很棒,我不知道下一个的额外参数。 仍然非常奇怪,而且与生成器使用的any一样有效率。 - Matthew Story

1

您可以使用列表推导式,它只是一种简洁的方式来执行循环和条件语句。

下面的列表推导式将在member_id存在时返回颜色值。如果您检查返回的列表至少有一个值,则知道member_id至少出现在一个颜色字典中。如果您制作两行并分配输出,您也可以方便地使用颜色字典,以防需要修改或读取其状态。

any([color for color in colorDict if member_id in colorDict[color]['members']])

我认为这比您问题中的示例更具Python风格,但有时候当涉及到更多复杂性时,列表推导式可能不够清晰。例如,如果您需要两个循环和两个条件,则列表推导式可能不是最佳选择。总体而言,它们是极其有用的工具,但是由您决定何时使用它们。


1
我认为这不会起作用。也许你的意思是 ... in colorDict[color]['members']?另外,你的方括号没有平衡。 - Selcuk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接