Конвертировать double для l oop для понимания двойного списка в Python 3? - PullRequest
0 голосов
/ 25 января 2020

Учитывая следующую структуру / logi c:

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])) 

и продолжить с логикой c. Посоветуйте, пожалуйста, как мне это сделать?

Мне удалось создать первый шаг:

[(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]}

Просто чтобы было понятно - цель состоит в том, чтобы создать уникальные наборы идентификаторов лекарств (2,3), (2,1548), ..., (3, 1548), ..., а не (3,2), (1548,2), et c или аналогичные, и представить их взаимодействия.

1 Ответ

2 голосов
/ 25 января 2020

Вы здесь все усложняете. Вам не нужно запускать несколько запросов в al oop, просто используйте один запрос :

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"] передаются обоим in (....) условиям, но затем ограничить базу данных только допустимыми комбинациями с предложением d1.id < d2.id. Это генерирует полный набор возможных (упорядоченных) комбинаций между d1.id и d2.id, как у вас для l oop, хотя и со строгим отсортированным порядком (с использованием (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[...]) test вместо ... 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()

Если это было невозможно, немного сложнее превратить ваши циклы в понимание списка. Не потому, что списочные выражения не могут обрабатывать вложенные циклы (просто перечислять их во вложенном порядке слева направо), а потому, что вам нужно использовать множественные операторы в теле l oop для получения результирующих значений. Тем не менее, поскольку * psychog2 cursor.execute() всегда возвращает None, вы можете использовать cursor.execute(...) or cursor для создания следующего итератора до l oop, так что у вас будет что-то вроде:

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

Это использует тот факт, что вы можете l oop прямо над курсором, чтобы получить строки. В любом случае, нет необходимости вызывать cursor.fetchall() и не нужно проверять, были ли результаты для этого указанного c запроса.

Ваши вложенные циклы 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)]

Однако, это совсем не эффективно (отправка множества отдельных запросов в базу данных), и при этом оно не настолько читабельно. И не обязательно, как показано выше.

Если вы должны иметь более жесткий контроль по-прежнему над своими парами идентификаторов, вам придется использовать вложенный тест кортежа; поместите столбцы d1.id и d2.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()
...