Получить, где элемент появляется внутри каждого подсписка в Python

#python #python-3.x #list #variables

#python #python-3.x #Список #переменные

Вопрос:

У меня есть следующий список списков:

 db=[['C','A','G','A','A','G','T'],['T','G','A','C','A','G'],['G','A','A','G','T']]
  

Мне нужно получить, где каждый отдельный символ (то есть, ['C', 'A', 'G', 'T'] ) появляется внутри каждого подсписка. В конце результатом должен быть кортеж, содержащий символ, и список кортежей, содержащих индекс подсписка, в котором появляется символ, и список индексов, представляющих, в какой позиции такого подсписка появляется символ

То есть:

 FinalList=[('C',[(0,[0]),(1,[3])]),
           ('A',[(0,[1,2,4]),(1,[2,4]),(2,[1,2])]),
           ('G',[(0,[2,5]),(1,[1,5]),(2,[0,3])]),
           ('T',[(0,[6]),(1,[0]),(2,[4])])  
           ]   
  

Чтобы лучше объяснить результат, давайте возьмем первый элемент FinalList .

 ('C',[(0,[0]),(1,[3])])
  

Здесь ‘ C' — это символ, потому 'C' что появляется в db[0] и db[1] , но не в db[2] , у нас есть [(0,[0]),(1,[3])] . Кроме того, поскольку in db[0] , 'C' появляется в позиции 0, мы имеем (0,[0]) , и поскольку in db[1] 'C' появляется в позиции 3, мы имеем (1,[3])

Единственное, что мне удалось сделать, это извлечь каждый уникальный символ с помощью следующего кода, хотя я считаю, что это неэффективно, поскольку он объединяет каждый список, а затем превращает результат в словарь, что потребовало бы времени для запуска, если db бы было больше элементов

 symbols=[]
for i in db:
    symbols =i
symbols=list(dict.fromkeys(symbols))
  

Теперь я планировал сравнить каждый элемент в символах с каждым элементом в БД, а затем сохранить индекс, в котором символы совпадают, но я думаю, что было бы неэффективно использовать циклы for внутри циклов for. Но я застрял здесь и не знаю, как поступить.

Ответ №1:

Это можно сделать чистым способом, выполнив итерацию исходных данных только один раз, создав промежуточную структуру, dict с базами в качестве ключей, значениями которых являются dicts с индексами подсписка в качестве ключей и значениями которых являются индексы баз в подсписках (ну, смотрите Пример в комментарии). Затем мы просто преобразуем его, чтобы построить окончательный список, структурированный так, как вы хотите:

 from collections import defaultdict

db=[['C','A','G','A','A','G','T'],['T','G','A','C','A','G'],['G','A','A','G','T']]

bases = ['C', 'A', 'G', 'T']
by_base = {base: defaultdict(list) for base in bases}

for sublist_idx, sublist in enumerate(db):
    for base_idx, base in enumerate(sublist):
        by_base[base][sublist_idx].append(base_idx)
        
# by_base looks like {'C': defaultdict(<class 'list'>, {0: [0], 1: [3]}), ...}


final_list = [(base, list(occurences.items())) for base, occurences in by_base.items()]
  

что дает нам:

 print(final_list)
# [('C', [(0, [0]), (1, [3])]), ('A', [(0, [1, 3, 4]), (1, [2, 4]), (2, [1, 2])]), ('G', [(0, [2, 5]), (1, [1, 5]), (2, [0, 3])]), ('T', [(0, [6]), (1, [0]), (2, [4])])]
  

Ответ №2:

Попробуйте этот код:

 db=[['C','A','G','A','A','G','T'],
    ['T','G','A','C','A','G'],
    ['G','A','A','G','T']]

ltrs = set()  # unique letter list

for x in db:
  for y in x:
     ltrs.add(y)

d = {x:[] for x in ltrs}  # main list

for k in d:  # each letter
    for xi,x in enumerate(db):  # each list in main list
      q = []
      for yi,y in enumerate(x):  # each letter in sublist
         if y == k:
            q.append(yi)  # add index to sublist
      if len(q):
         d[k].append((xi,q)) # add tuple to main list
         
print([(k,d[k]) for k in d])
  

Вывод

 [('C', [(0, [0]), (1, [3])]), 
 ('G', [(0, [2, 5]), (1, [1, 5]), (2, [0, 3])]), 
 ('A', [(0, [1, 3, 4]), (1, [2, 4]), (2, [1, 2])]), 
 ('T', [(0, [6]), (1, [0]), (2, [4])])]
  

Ответ №3:

Ниже

 SYMBOLS = {'A', 'C', 'T', 'G'}
db = [['C', 'A', 'G', 'A', 'A', 'G', 'T'], ['T', 'G', 'A', 'C', 'A', 'G'], ['G', 'A', 'A', 'G', 'T']]
final_list = []
for sym in SYMBOLS:
    lst = []
    for idx1, entry in enumerate(db):
        found = False
        for idx2, s in enumerate(entry):
            if s == sym:
                if not found:
                    lst.append((idx1, [idx2]))
                    found = True
                else:
                    lst[-1][1].append(idx2)
    final_list.append((sym, lst))
for entry in final_list:
    print(entry)
  

вывод

 ('G', [(0, [2, 5]), (1, [1, 5]), (2, [0, 3])])
('A', [(0, [1, 3, 4]), (1, [2, 4]), (2, [1, 2])])
('T', [(0, [6]), (1, [0]), (2, [4])])
('C', [(0, [0]), (1, [3])])
  

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

1. https://docs.python.org/3/library/functions.html#enumerate

Ответ №4:

Вы могли бы достичь этого, используя понимание списка:

 chars = ['C', 'A', 'G', 'T']
final_list = [
  (character, 
    [
      (i, indexes) for i, indexes in
        [(i, [j for j, c in enumerate(l) if c == character]) for i, l in enumerate(db)]
      if len(indexes) > 0
    ]
  ) for character in chars
]