накопление значений для соответствующего ключа в словаре?

#python #python-3.x

#python #python-3.x

Вопрос:

Я пытаюсь найти позиции баз (A, C, G, T) и поместить их в словарь, соответствующий их позициям.

Я работаю с текстовым файлом, который содержит базовые строки, подобные приведенным ниже

 ----T
C
-C
-----G
C
-----C
---T
----A
----C
-----G
  

Из приведенной выше информации я знаю, что

  • C находится на 1-й позиции

  • C находится на 2-й позиции

  • база 3-й позиции неизвестна

  • T находится на 4-й позиции

  • C, A, T находятся на 5-й позиции

  • C, G находятся на 6-й позиции

На данный момент я написал приведенный ниже код

 def chunks(chunks_file):
    set_bases = {}
    with open(chunks_file) as file:
        for line in file:
            for character in line:
                if character.isalpha():
                    letter = character
                    position = line.find(letter)   1
                    set_bases[position] = {letter}

    return set_bases
  

мой текущий результат:

 {5: {'C'}, 1: {'C'}, 2: {'C'}, 6: {'G'}, 4: {'T'}}
  

где в качестве желаемого результата будет :

 {1: {'C'}, 2: {'C'}, 4: {'T'}, 5: {'C', 'A', 'T'}, 6: {'C', 'G'}}
  

Мне кажется, что значения не добавляются к уже существующим ключам, но новые значения заменяют старые значения.

Как я могу решить эту проблему?

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

1. попробуйте set_bases[position].add(letter) . Прямо сейчас вы каждый раз заменяете ключ dict новым набором.

2. Действительно ли каждая строка файла содержит только 0 или более тире, за которыми следует ровно один экземпляр A, C, G или T, а затем конец строки? Если да, то каждая строка может быть сведена к целочисленному индексу и букве. И для этого вам даже не понадобилось бы регулярное выражение, вы могли бы напрямую использовать строковые методы. Вы могли бы объявить список набора или list-of-dict максимально возможной длины строки, затем вставить каждую букву непосредственно в dict / set с соответствующим индексом. Это позволило бы вам один раз выполнить итерацию по входному файлу, и не было бы необходимости сохранять его содержимое.

Ответ №1:

Вы можете сделать это следующим образом, принимая во внимание, что у вас есть txt файл:

 outDict = {}

with open('data.txt', 'r') as inFile:
    lines = [line.strip() for line in inFile if not line == 'n']
    outDict = dict((str(line.count('-') 1),set()) for line in lines)
    for line in lines:
        outDict[str(line.count('-') 1)].update(line[-1])
    print(outDict)
  

Результат:

 {'5': {'C', 'A', 'T'}, '1': {'C'}, '2': {'C'}, '6': {'C', 'G'}, '4': {'T'}}
  

Ответ №2:

Я могу предложить следующие улучшения:

 import collections

def chunks(filename):
    bases = collections.defaultdict(set)

    with open(filename) as f:
        for line in f:
            line = line.strip()
            if len(line) > 0:
                for i, char in enumerate(line):
                    if char.isalpha():
                        position = i   1
                        bases[position].add(char)

    return bases
  
  • Этот код использует collections.defaultdict , поэтому вам не нужно проверять, присутствует ли позиция в dict или нет.
  • Я также использую enumerate() при переборе строк, так что у вас уже есть позиция и вызывать не нужно line.find() .

Этот код можно использовать следующим образом:

 >>> d = chunks('your-file-name.txt')
>>> d
defaultdict(<class 'set'>, {5: {'T', 'C', 'A'}, 1: {'C'}, 2: {'C'}, 6: {'G', 'C'}, 4: {'T'}})

>>> dict(d)
{5: {'C', 'A', 'T'}, 1: {'C'}, 2: {'C'}, 6: {'G', 'C'}, 4: {'T'}}

>>> for k, v in sorted(d.items()):
...     print(k, v)
1 {'C'}
2 {'C'}
4 {'T'}
5 {'C', 'A', 'T'}
6 {'G', 'C'}
  

Ответ №3:

Попробуйте что-то вроде этого:

 def chunks(chunks_file):
    set_bases = {}
    with open(chunks_file) as file:
        for line in file:
            for character in line:
                if character.isalpha():
                    letter = character
                    position = line.find(letter)   1
                    if position in set_bases:
                        set_bases[position].append(letter)
                    else:
                        set_bases[position] = [letter]

    return set_bases