Как определить частичные совпадения кортежей в списке кортежей

#python #dictionary #tuples

#python #словарь #кортежи

Вопрос:

Если у меня есть словарь, состоящий из списка кортежей, подобных so:

 d = {'ENSG00000186092': [('ENST00000641515', '3'),
                        ('ENST00000641515', '1'),
                        ('ENST00000641515', '2'),
                        ('ENST00000335137', '1')],
    'ENSG00000284662': [('ENST00000332831', '1')],
    'ENSG00000284733': [('ENST00000426406', '1')]}
  

Как я могу определить, существуют ли для каждого ключа кортежи, в которых первый элемент кортежей не совпадает, но совпадают вторые элементы?

Например, в приведенном выше примере мы бы увидели только одно «попадание», и это было бы для ключа ENSG00000186092 из-за:

 ('ENST00000641515', '1')
('ENST00000335137', '1')
  

Ответ №1:

Вас заинтересует запутанное понимание списка?

 [
  k for k, v in d.items()
  if any(
    (i, j)
    for i, j in v
    for x, y in v
    if i != x and j == y
  )
]
>>> ['ENSG00000186092']
  
  1. Циклы по словарю
  2. Перебирает список кортежей для каждого ключа
  3. Для каждого кортежа выполните цикл по одному и тому же списку и проверьте, не совпадают ли первые записи, но совпадают вторые
  4. Если таковые найдутся, запишите этот ключ с шага 2.

Комментарии:

1. Мне это кажется прекрасным! Если я хочу, чтобы на выходе были соответствующие кортежи вместо ключа, как мне это сделать?

2. Измените элемент, который хранится в результирующем списке; эта строка k for k, v in d.items() становится v for k, v in d.items() (или действительно v for _, v in d.items() , потому что k не используется).

3. О, подождите, это возвращает все кортежи для совпадающих ключей.

4. Вы можете просмотреть список и использовать ключи для извлечения списков кортежей, а затем выполнить с ними ту же логику, что и внутри any() функции: [(i, j) for k in [k for k, v in d.items() if any((i, j) for i, j in v for x, y in v if i != x and j == y)] for i, j in d[k] for x, y in d[k] if i != x and j == y] . Теперь это действительно начинает обретать форму! Ужасная форма.

5. Хорошо, я попробовал это и заметил, что в результате получаю дубликаты, поэтому я попытался настроить результат, но продолжаю получать ошибки типа unhashable type 'list'

Ответ №2:

 d = {'ENSG00000186092': [('ENST00000641515', '3'),
                        ('ENST00000641515', '1'),
                        ('ENST00000641515', '2'),
                        ('ENST00000335137', '1')],
    'ENSG00000284662': [('ENST00000332831', '1')],
    'ENSG00000284733': [('ENST00000426406', '1')]}

for k, a in d.items():
    a_s = sorted(a, key=lambda x: (x[1], x[0]))
    for i in range(len(a_s)-1):
        if a_s[i][1] == a_s[i 1][1] and a_s[i][0] != a_s[i 1][0]:
            print (k, a_s[i], a_s[i 1])
  
  • Сортируйте кортежи по второму элементу, затем по первому элементу кортежей, чтобы кортежи объединялись по второму элементу, а затем по первому элементу
  • Проверьте условие между текущим кортежем и следующим кортежем в отсортированном списке и распечатайте их, если условие выполнено
  • Временная сложность если d имеет k элементы и размер списка равен ‘n’, то это O(k*nlogn) [ k для внешнего цикла и nlogn для сортировки]

Ответ №3:

Быть очень подробным:

 d = {
    "ENSG00000186092": [
        ("ENST00000641515", "3"),
        ("ENST00000641515", "1"),
        ("ENST00000641515", "2"),
        ("ENST00000335137", "1"),
    ],
    "ENSG00000284662": [("ENST00000332831", "1")],
    "ENSG00000284733": [("ENST00000426406", "1")],
}

def has_duplicates(list_of_tuples):
    seen = set()
    for _, value in list_of_tuples:
        if value in seen:
            return True
        seen.add(value)
    return False

dupes = [key for key, value in d.items() if has_duplicates(value)]

print(dupes)
  

has_duplicates Функция принимает значение из вашего словаря. Возвращает True, если какой-либо из кортежей в этом значении имеет то же второе значение.

Понимание списка при возврате дает вам, что все ключи были has_duplicates истинными.