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

Я читаю файл данных. Строки начинаются с последовательных цифр (шагов), а иногда между каждой строкой стоит 0.

E.g:

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

Как я могу создать список, который подсчитывает количество 0 между каждым шагом.

Я хочу такой список:

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

который представляет количество нулей, содержащихся на каждом шаге, то есть: шаг 1 имеет 1 ноль, шаг 2 имеет 1 ноль, шаг 3 имеет 0 нулей, шаг 4 имеет 0 нулей, шаг 5 имеет 3 нуля и шаг 6 имеет 1 ноль.


person Mike Issa    schedule 21.12.2015    source источник
comment
Можешь показать свою попытку?   -  person Ahsanul Haque    schedule 21.12.2015


Ответы (5)


Следующий код должен работать, если ваш файл данных выглядит точно так, как вы описали (например, нет другого числа, кроме возрастающего числа шагов и нулей).

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
person Ilya V. Schurov    schedule 21.12.2015
comment
Вы должны привести к int или сравнить с char "0", я подозреваю, что иначе это не сработает. - person Delgan; 21.12.2015
comment
Это не сработает по крайней мере в трех случаях: вы пытаетесь strip создать файл; вы сравниваете результат с целым числом; и вы используете append как функцию. И это еще до того, как я смог запустить его, чтобы увидеть, правильный ли ответ! - person DSM; 21.12.2015
comment
Это сработало в моей ситуации. Я не использовал line.strip(), я использовал f=f.readlines, затем for line in f: if line[0] == 0: cur+=1 и т. д. Спасибо за помощь! Очень признателен :) - person Mike Issa; 21.12.2015
comment
@MikeIssa: не используйте f = f.readlines(), если он вам не нужен как list; который загружает весь файл в память (с неограниченными накладными расходами памяти). Если вы можете обрабатывать построчно, сделайте это. - person ShadowRanger; 21.12.2015
comment
Да, спасибо, @ShadowRanger, я знаю об этом. Однако в моей ситуации мне нужно, чтобы каждая целая строка была преобразована в элементы списка; но вы правы насчет использования памяти. - person Mike Issa; 21.12.2015

Возможно, слишком умное решение с использованием включенных в 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 преобразования достигает той же цели.

person ShadowRanger    schedule 21.12.2015

Я придумал это:

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)
person Roberto    schedule 21.12.2015
comment
Спасибо вам за помощь! Этот код был протестирован и работает для моей ситуации. - person Mike Issa; 21.12.2015

Альтернативное решение

# 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)]
person Tomasz Jakub Rup    schedule 21.12.2015
comment
Спасибо @Tomasz. Коротко и мило :) - person Mike Issa; 21.12.2015

person    schedule
comment
Спасибо @Pulkit. Это было полезно :) - person Mike Issa; 21.12.2015