繁体   English   中英

在 Python 3 中将双循环转换为双列表理解?

[英]Convert double for loop to double list comprehension in Python 3?

鉴于以下结构/逻辑:

for i in range(len(drug_list["drug_list_ids"])):
      for j in range(i + 1, len(drug_list_ids["drug_list_ids"])):
               with pg_get_cursor(pool) as cursor:
                     q = """ SELECT d1.name as drug_1, d2.name as drug_2, description
                             FROM interactions i, drugs d1, drugs d2
                             WHERE d1.id = %s
                             AND d2.id = %s
                             AND i.id1 = d1.id
                             AND i.id2 = d2.id; """
                     cursor.execute(q, (drug_list["drug_list_ids"][i], drug_list["drug_list_ids"][j]))
                     res = cursor.fetchall()

                     if res:
                         for d in res:
                             ddi_list.append(d)

我想将其转换为双重列表理解,将其传递给我的

cursor.execute(q, (drug_list["drug_list_ids"][i], drug_list["drug_list_ids"][j])) 

并继续逻辑。 请告知我该怎么做?

我设法创建了第一步:

[(i,j) for i in range(len(drug_list["drug_list_ids"])) for j in range(i + 1, len(drug_list["drug_list_ids"]))]

我的字典: {'drug_list': ['dabigatran etexilate', 'dasatinib', 'lepirudin', 'atosiban', 'glycocholic acid'], 'drug_list_ids': [2, 3, 1548, 3579, 8]}

只是为了说明清楚 - 目标是制作药物 ID (2,3) , (2,1548) , ..., (3, 1548) , ... 而不是(3,2)唯一元组, (1548,2)等或类似的,并展示他们的互动。

你在这里把事情复杂化了。 您不需要在循环中运行多个查询,只需使用单个查询

SELECT d1.name as drug_1, d2.name as drug_2, description
FROM interactions i
INNER JOIN drugs d1 ON i.id1 = d1.id
INNER JOIN drugs d2 ON i.id2 = d2.id
WHERE
    d1.id in (... id list, see below ...)
AND d2.id = (... same id list, see below ...)
AND d1.id < d2.id

我在这里使用INNER JOIN语法而不是FROM子句中的多个表将连接条件分组到一个专用位置,因此WHERE条件更容易推理。

以上将您的所有drug_list["drug_list_ids"] id 传递给in (....)条件,但随后将数据库限制为仅使用具有d1.id < d2.id子句的有效组合。 这会在d1.idd2.id之间生成一整套可能的(有序)组合,就像你的 for 循环一样,尽管使用严格的排序顺序(使用(8, 1548)(8, 3579)而不是(1548, 8)(3579, 8) )。

Psycopg2 实际上接受元组作为占位符值,并将它们扩展为正确的语法,用于... IN ...测试; 在这种情况下,驱动程序包括括号:

query_string = """\
    SELECT d1.name as drug_1, d2.name as drug_2, description
    FROM interactions i
    INNER JOIN drugs d1 ON i.id1 = d1.id
    INNER JOIN drugs d2 ON i.id2 = d2.id
    WHERE
        d1.id in %s
    AND d2.id in %s
    AND d1.id < d2.id
"""
with pg_get_cursor(pool) as cursor:
    cursor.execute(query_string, (
        tuple(drug_list["drug_list_ids"]),
        tuple(drug_list["drug_list_ids"])
    ))
    ddi_list = cursor.fetchall()

或者您可以使用 Postgres ... = ANY(ARRAY[...])测试而不是... IN ... ,并利用psycopg2 将列表插入为ARRAY这一事实:

query_string = """\
    SELECT d1.name as drug_1, d2.name as drug_2, description
    FROM interactions i
    INNER JOIN drugs d1 ON i.id1 = d1.id
    INNER JOIN drugs d2 ON i.id2 = d2.id
    WHERE
        d1.id = ANY(%s)
    AND d2.id = ANY(%s)
    AND d1.id < d2.id
"""
with pg_get_cursor(pool) as cursor:
    cursor.execute(query_string, (drug_list["drug_list_ids"], drug_list["drug_list_ids"]))
    ddi_list = cursor.fetchall()

如果这是不可能的,将您的循环转换为列表理解有点棘手。 不是因为列表推导式无法处理嵌套循环(只需按嵌套顺序从左到右列出它们),而是因为您需要在循环体中使用多个语句来生成结果值。 尽管如此,因为 psycopg2 的cursor.execute()总是返回None ,你可以使用cursor.execute(...) or cursor来生成下一个迭代器来循环,所以你会有类似的东西:

[v ... for ... in outer loops ... for v in (cursor.execute(...) or cursor)]

这利用了您可以直接在游标上循环以获取行的事实。 无论如何,都不需要调用cursor.fetchall()也不需要测试该特定查询是否有结果。

您的嵌套for循环可以用itertools.combinations()更简洁地表达:

from itertools import combinations
query_string = """\
    SELECT d1.name as drug_1, d2.name as drug_2, description
    FROM interactions i
    INNER JOIN drugs d1 ON i.id1 = d1.id
    INNER JOIN drugs d2 ON i.id2 = d2.id
    WHERE d1.id = %s AND d2.id = %s
"""
with pg_get_cursor(pool) as cursor:
    combos = combinations(drug_list["drug_list_ids"], r=2)
    ddi_list = [v for id1, id2 in combos for v in (cursor.execute(query_string, (id1, id2)) or cursor)]

然而,这根本不是有效的(向数据库发送单独的查询负载),也不是那么可读。 并且没有必要,如上所示。

如果您必须对 id 配对进行更严格的控制,则必须使用嵌套元组测试; d1.idd2.id列放入一个数组中,并在d1.id使用IN ((v1, v2), (v3, v4), ...)测试,传递给cursor.execute()作为元组的元组:

from itertools import combinations

query_string = """\
    SELECT d1.name as drug_1, d2.name as drug_2, description
    FROM interactions i
    INNER JOIN drugs d1 ON i.id1 = d1.id
    INNER JOIN drugs d2 ON i.id2 = d2.id
    WHERE
        (d1.id, d2.id) IN %s
"""

# list of [id1, id2] lists
combos = tuple(combinations(drug_list["drug_list_ids"], r=2))
with pg_get_cursor(pool) as cursor:
    cursor.execute(query_string, (combos,))
    ddi_list = cursor.fetchall()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM