1

Я написал функцию, которая позволяет мне просматривать список, сравнивать значения с предшественниками и утверждать, в какой момент список становится «стабильным» для определенного количества записей. Значения в списке представляют собой сигнал, который может достигать или не достигать стабильной точки. я пришел с этим:Подробнее pythonic способ фильтрации стабильных значений в списке

def unstableFor(points, maxStable): 
    count = 0; 
    prev = points[0] 
    for i in range(1, len(points)): 
     if points[i] == prev: 
      count = count + 1 
     else: 
      count = 0 
      prev = points[i] 
     if count >= maxStable: 
      return i 
    return len(points) - 1 

Возвращаемое значение затем используется вызывающим убирания последнюю часть списка.

Выполняет свою работу, однако, я очень недоволен тем, насколько громоздким оно выглядит. Можете ли вы представить себе более питоновский, возможно, чисто функциональный способ выполнения этой операции фильтрации?

+2

На стороне записки, я думаю, что 'count' следует начинать с 1 –

+3

Можно также показать список ввода пробы и ожидаемый результат –

+0

должны быть записи всегда подряд, чтобы стать стабильным? –

ответ

2

Использование перечисления и архивирования:

def unstableFor (points, threshold): 
    for i, (a, b) in enumerate(zip(points, points[1:])): 
     count = count + 1 if a == b else 0 
     if count >= threshold: 
      return i 
    return i 
+1

'zip (points, points [1:])' более экономичен с точки зрения использования памяти, чем 'zip (точки [: - 1], points [1:])', и оба они дают тот же результат в Python 2 и 3 соответственно. –

+0

@JacquesGaudin спасибо! – Uriel

+0

Я считаю, что это очень хорошее сочетание императивного и функционального: оно ясное и очень компактное. Ницца. –

1

Вот эскиз функционального подхода. Это немного загадочно. Действительно, я, скорее всего, буду использовать ваш подход (используя enumerate, как идиоматический способ, а не range(len(x))). Во всяком случае, предположим, max_stable 3:

>>> from itertools import groupby 
>>> grouped = groupby(enumerate(x), lambda i_e: i_e[1]) 
>>> gen = (g for g in map(lambda e: list(e[1]), grouped) if len(g) >= 3) 
>>> run = next(gen) 
>>> run[2][0] 
10 

Здесь очищается:

>>> from operator import itemgetter 
>>> from itertools import islice 
>>> def unstable_for(points, max_stable): 
...  grouped = groupby(enumerate(points), itemgetter(1)) 
...  gen = (g for g in (tuple(gg) for _, gg in grouped) if len(g) >= max_stable) 
...  run = tuple(islice(gen,1)) 
...  if len(run) == 0: 
...   return len(points) - 1 
...  else: 
...   return run[0][max_stable - 1][0] 
... 
>>> x 
[1, 2, 3, 3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 9] 
>>> unstable_for(x, 3) 
10 
>>> unstable_for(x, 2) 
3 
>>> unstable_for(x, 1) 
0 
>>> unstable_for(x, 20) 
13 
>>> 

Не очень элегантно. Опять же, я бы пошел с императивным решением. Возможно, у кого-то есть более элегантное функциональное решение.

1

Ваш код выглядит хорошо для меня: его легко читать и понимать. Я бы просто удалить некоторые повторы, чтобы сделать его выглядеть следующим образом:

def unstableFor(points, maxStable): 
    prev = None # assuming None is not member of points 
    for i, point in enumerate(points): 
     if point == prev: 
      count = count + 1 
     else: 
      count = 0 
      prev = point 
     if count >= maxStable: 
      break 
    return i 
+0

Я бы сказал, что это самый * Pythonic * способ. –

Смежные вопросы