从列表中获取相关词典

时间:2014-07-04 15:28:52

标签: python list

我有两个不同的词典列表(ListA和ListB)。

listA中的所有词典都有字段" id"和" external_id" listB中的所有字典都有字段" num"和" external_num"

我需要获取所有字典对,其中external_id = num的值和external_num = id的值。

我可以使用此代码实现这一目标:

for dictA in ListA:
    for dictB in ListB:
        if dictA["id"] == dictB["external_num"] and dictA["external_id"] == dictB["num"]:

但是我看到了许多漂亮的python表达式,我想有可能让这个结果更加pythonic风格,不是吗?

我喜欢:

res = [A, B for A, B in listA, listB if A['id'] == B['extnum'] and A['ext'] == B['num']]

2 个答案:

答案 0 :(得分:3)

你非常接近,但是你并没有告诉Python你想如何连接这两个列表以获得字典对AB

如果您想将ListA中的所有词典与ListB中的所有词典进行比较,则需要itertools.product

from itertools import product

res = [A, B for A, B in product(ListA, ListB) if ...]

或者,如果您希望对具有相同的索引,请使用zip

res = [A, B for A, B in zip(ListA, ListB) if ...]

如果您不想立即构建整个列表,请注意您可以使用itertools.ifilter选择所需的对:

from itertools import ifilter, product

for A, B in ifilter(lambda (A, B): ..., 
                    product(ListA, ListB)):
    # do whatever you want with A and B

(如果您使用zip执行此操作,请改用itertools.izip以最大限度地提高效果。)


关于Python 3.x的注释:

  • zipfilter no longer return lists因此itertools.izipitertools.ifilter不再存在(正如range推出xrange }),您只需要product中的itertools;和
  • lambda (A, B):no longer valid syntax;你需要编写过滤函数来获取单个元组参数lambda t:,例如将A替换为t[0]

答案 1 :(得分:1)

首先,为了代码清晰,我实际上可能会选择你的第一个选项 - 在这种情况下,我不认为使用for循环特别是非Pythonic。但是,如果您想尝试使用列表推导,有几点需要注意:

列表推导返回的每个项目都只需要一个单项。尝试返回A, B会给你一个SyntaxError。但是,您可以返回列表或元组(或其他任何内容,即单个对象),因此res = [(A,B) for...]之类的内容将开始工作。

另一个问题是你是如何迭代这些列表的 - 从你的第一段代码开始,看起来你没有对这些列表排队做出任何假设,这意味着:如果你的第二项似乎没问题{1}}与listA中的第14项匹配,只要它们在相应字段上匹配即可。这是完全合理的,但请注意,无论您如何尝试,都需要两个listB循环*。你仍然需要你的比较。因此,作为列表理解,您可以尝试:

for

然后,在res = [(A, B) for A in listA for B in listB if A['id']==B['extnum'] and A['extid']==B['num']]中,您将拥有0个或更多元组,每个元组将包含您感兴趣的相应字典。要使用它们:

res

或更简洁(和Python):

for tup in res:
    A = tup[0]
    B = tup[1]
    #....

因为Python非常聪明,知道它产生了一个包含2个元素的项目(元组),所以它可以直接将它们分配给for A,B in res: #... A

编辑:*回想起来,你需要两个B循环并不完全正确,如果你的列表足够大,那么制作一个中间字典可能会有所帮助。这样:

for

并且,如果# make a dictionary with key=tuple, value=dictionary interim = {(A['id'], A['extid']): A for A in listA} for B in listB: tup = (B['extnum'], B['num']) ## order matters! match-up with A if tup in interim: A = interim[tup] print(A, B) - id对不希望在listA中的所有项目中都是唯一的,那么您需要使用extid来查看collections.defaultdict ......但我不确定这仍然适合“更多Pythonic”类别。

我意识到这对你提出的问题可能有些过分,但我不能让我的'list循环声明成立,因为它并不完全正确。