计算列表中特定元素在其他元素之间出现的次数。

3

我是一名数据文件读取助手。每行都以连续的数字(步骤)开头,有时在每行之间会有一个 0。

例如:

1
0
2
0
3
4
5
0
0
0
6
0

如何创建一个能够计算每个步骤之间0的数量的列表。

我想要一个类似这样的列表:

finalList = [1,1,0,0,3,1]

这表示每个步骤包含的0的数量,例如:第一步有1个零,第二步有1个零,第三步没有零,第四步没有零,第五步有3个零,第六步有1个零。


2
你能展示一下你的尝试吗? - Ahsanul Haque
5个回答

3
如果您的数据文件完全符合您描述的条件(例如,步骤递增且为零以外没有其他数字),则以下代码应该可以正常工作。
cur = 0
res = []
with open("file.txt") as f:
    for line in f:
        if line.strip() == '0':
            cur += 1
        else:
            res.append(cur)
            cur = 0

1
你应该转换为 int 或与字符 "0" 进行比较,否则可能不起作用。 - Delgan
4
这种做法至少有三个问题:你试图strip一个文件;你将结果与整数进行比较;你将append用作函数。而且,在我运行它之前,这些问题就已经存在了,我都还没来得及看答案是否正确! - DSM
1
这在我的情况下起作用了。虽然我没有使用 line.strip(),但我使用了 f=f.readlines 然后 for line in f: if line[0] == 0: cur+=1 等等... 谢谢你的帮助!非常感激 :) - Mike Issa
1
@MikeIssa:如果你不需要将文件读入一个列表中,请不要使用f = f.readlines();这会将整个文件读入内存(导致无限制的内存开销)。如果你可以逐行处理,请这样做。 - ShadowRanger
是的,谢谢@ShadowRanger,我知道那个问题。不过在我的情况下,我需要把每一行都转换成一个列表的元素;但你对内存使用的观点是正确的。 - Mike Issa

2
a = [1,0,2,0,3,4,5,0,0,0,6,0]
finalList = []
count = 0
for i in xrange(len(a)):
    if i == 0 : continue
    if a[i] == 0 :
        count += 1
    else : 
        finalList.append(count)
        count = 0
finalList.append(count)

1
谢谢@Pulkit。这很有帮助 :) - Mike Issa

2
可能过于聪明的解决方案,使用Python自带的工具包:
from itertools import chain, groupby

with open("file.txt") as f:
    # Add extra zeroes after non-zero values so we see a group when no padding exists
    extrazeroes = chain.from_iterable((x, 0) if x else (x,) for x in map(int, f))

    # Count elements in group and subtract 1 if not first group to account for padding
    # The filter condition means we drop non-zero values cheaply
    zerocounts = [sum(1 for _ in g) - bool(gnum) for gnum, (k, g) in enumerate(groupby(extrazeroes)) if k == 0]

    # If leading zeroes (before first non-zero line) can't happen, simplify to:
    zerocounts = [sum(1 for _ in g) - 1 for k, g in groupby(extrazeroes) if k == 0]

是的,这有点复杂(如果您不关心在两个非零值之间没有间隙时包含零,则会简单得多),但它很简洁,并且应该非常快。如果您可以省略计数中的0,它将简化为更加简洁的形式:

with open("file.txt") as f:
    zerocounts = [sum(1 for _ in g) for k, g in groupby(map(int, f)) if k == 0]

就记录而言,如果它符合要求,我会使用后者。前者可能不应该在生产代码中使用。 :-)

请注意,根据您的用例,对于更广泛的问题,使用 groupby 可能是一个好主意;在评论中,您提到您正在存储文件中的所有行(使用 f = f.readlines()),这意味着您将访问它们,可能基于存储在 zerocounts 中的值。如果您有一些特定的需要根据后面的零数来处理每个“步骤”,上面代码的改编可能会通过懒惰分组和处理来节省内存开销。

注意:为了避免将整个文件读入内存,在 Python 2 中,您需要添加 from future_builtins import map,因此 map 是像在 Py3 中一样的惰性生成器函数,而不是将整个文件加载并立即将其全部转换为 int。如果您不想踩 map,则导入并使用 itertools.imap 而不是 map 进行 int 转换可以实现相同的目标。


1
我想到了这个:

我想到了这个:

finalList = []
count = 0
step = None

for e in [1, 0, 2, 0, 3, 4, 5, 0, 0, 0, 6, 0]:
   if e > 0:
      if step:
         finalList.append(count)
      step = e
      count = 0
   else:
      count += 1
if step:
    finalList.append(count)

非常感谢您的帮助!这段代码已经经过测试,并且适用于我的情况。 - Mike Issa

0

另一种解决方案

# temp list (copy of l with last element if doesn't exist)
_l = l if l[-1] > 0 else l + [max(l) + 1]
# _l.index(i) - _l.index(i - 1) - 1 = distance between elements
[_l.index(i) - _l.index(i - 1) - 1 for i in range(2, max(_l) + 1)]

谢谢@Tomasz。简短而甜美 :) - Mike Issa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接