Python - 创建计数器和循环?

2 投票
3 回答
8138 浏览
提问于 2025-04-15 23:33

我在下面这段代码上遇到了一些问题:

输入:li 是一个嵌套列表,如下所示:

li = [['>0123456789 mouse gene 1\n', 'ATGTTGGGTT/CTTAGTTG\n', 'ATGGGGTTCCT/A\n'],   ['>9876543210 mouse gene 2\n', 'ATTTGGTTTCCT\n', 'ATTCAATTTTAAGGGGGGGG\n']]

我希望通过下面这个函数,得到的输出是每个子列表中,'>' 后面第2到第9位的数字,前提是这个子列表中 '/' 的数量大于1。

但是,我的代码却给出了所有条目的数字,而且还重复了很多次。因此,我觉得我的计数器和循环可能有问题,但我就是搞不清楚哪里出错了。

任何帮助都非常感谢。

import os

cwd = os.getcwd()


def func_one():
    outp = open('something.txt', 'w')       #output file
    li = []
    for i in os.listdir(cwd):           
        if i.endswith('.ext'):
            inp = open(i, 'r').readlines()
            li.append(inp)
    count = 0
    lis = []
    for i in li:
        for j in i:
            for k in j[1:]          #ignore first entry in sublist
                if k == '/':
                    count += 1
                if count > 1:
                    lis.append(i[0][1:10])      
                    next_func(lis, outp)

谢谢, S :-)

3 个回答

0
import itertools
import glob

lis = []
with open('output.txt', 'w') as outfile:
    for file in glob.iglob('*.ext'):
        content = open(file).read()
        if content.partition('\n')[2].count('/') > 1:
            lis.append(content[1:10])
            next_func(lis, outfile)

你看到所有条目都有数字的原因是因为你没有重置计数器。

8

Tamás 提出了一个不错的解决方案,虽然他的编程风格和你很不一样。不过,因为你问的是“我在下面的代码上遇到了一些问题”,所以我觉得我们需要更深入地讨论一下。

如何避免将来的这些问题

在你从“我觉得我知道怎么写这段代码”到真正有可用的代码的过程中,你犯了几个错误。

你给变量起了些没有意义的名字,这让理解你的代码变得几乎不可能,包括你自己。想“但我知道每个变量的意思”显然是错误的,否则你就能自己解决这个问题了。看看下面我修正你的代码的地方,你会发现描述和讨论你的代码有多困难。

你试图一次性解决整个问题,而不是把它拆分成小部分。写一些小函数或者代码片段,每次只做一件事。对于你正在处理的每一部分,确保它是正确的并进行测试。然后再写其他部分,可能会用到你已经写好的部分。我说的“部分”通常指的是函数、方法或类。

修正你的代码

这正是你所要求的,而其他人并没有做到这一点。

你需要把 count = 0 这一行移动到 for i in li: 这一行之后(适当地缩进)。这样可以在每个子列表开始时重置计数器。其次,一旦你向 lis 添加了内容并运行了 next_func,你需要跳出 for k in j[1:] 循环和外层的 for j in i: 循环。

这里有一个可以工作的代码示例(没有 next_func,但你可以在添加的地方加上):

>>> li = [['>0123456789 mouse gene 1\n', 'ATGTTGGGTT/CTTAGTTG\n', 'ATGGGGTTCCT/A\n'],   ['>9876543210 mouse gene 2\n', 'ATTTGGTTTCCT\n', 'ATTCAATTTTAAGGGGGGGG\n']]
>>> lis = []
>>> for i in li:
        count = 0
        for j in i:
            break_out = False
            for k in j[1:]:
                if k == '/':
                    count += 1
                if count > 1:
                    lis.append(i[0][1:10])
                    break_out = True
                    break
            if break_out:
                break

>>> lis
['012345678']

重写你的代码以提高可读性

这样你就能明白我在回答开始时所说的意思。

>>> def count_slashes(gene):
    "count the number of '/' character in the DNA sequences of the gene."
    count = 0
    dna_sequences = gene[1:]
    for sequence in dna_sequences:
        count += sequence.count('/')
    return count
>>> def get_gene_name(gene):
    "get the name of the gene"
    gene_title_line = gene[0]
    gene_name = gene_title_line[1:10]
    return gene_name
>>> genes = [['>0123456789 mouse gene 1\n', 'ATGTTGGGTT/CTTAGTTG\n', 'ATGGGGTTCCT/A\n'],   ['>9876543210 mouse gene 2\n', 'ATTTGGTTTCCT\n', 'ATTCAATTTTAAGGGGGGGG\n']]
>>> results = []
>>> for gene in genes:
        if count_slashes(gene) > 1:
            results.append(get_gene_name(gene))

>>> results
['012345678']
>>> 
9

你的缩进可能有问题,你应该在 for j in i 循环里面检查 count > 1,而不是在检查每个字符的 j[1:] 的那个循环里。

另外,这里有一个更简单的方法来做同样的事情:

def count_slashes(items):
    return sum(item.count('/') for item in items)

for item in li:
    if count_slashes(item[1:]) > 1:
        print item[0][1:10]

或者,如果你需要把 ID 放在一个列表里:

result = [item[0][1:10] for item in li if count_slashes(item[1:]) > 1]

Python 的 列表推导式生成器表达式 是非常强大的工具,建议你学习如何使用它们,这样会让你的编程生活简单很多。上面的 count_slashes 函数使用了生成器表达式,而我最后的代码片段则使用了列表推导式,以一种简洁的方式构建结果列表。

撰写回答