【问题标题】:More pythonic way of filtering out stable values in a list过滤列表中稳定值的更多pythonic方法
【发布时间】:2017-06-07 19:22:55
【问题描述】:

我编写了一个函数,它允许我遍历一个列表,将值与前任进行比较,并断言在该点列表对于一定数量的条目变得“稳定”。 列表中的值代表一个信号,可能会或不会达到稳定点。 我想出了这个:

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

然后调用者使用返回的值来删除列表的最后一部分。

它完成了它的工作,但是,我对它看起来多么笨重很不满意。你能想出一种更 Python 的、可能是纯函数式的方式来执行这个过滤操作吗?

【问题讨论】:

  • 附带说明,我认为count 应该从 1 开始
  • 您还可以显示示例输入列表和预期输出
  • 条目是否必须始终连续才能获得稳定的资格?
  • 是的,它们必须是后续的

标签: python list functional-programming filtering purely-functional


【解决方案1】:

使用枚举和压缩:

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

【讨论】:

  • zip(points, points[1:]) 在内存使用方面比zip(points[:-1], points[1:]) 更经济,并且它们在 Python 2 和 3 中分别产生相同的结果。
  • 我相信这是命令式和函数式的完美结合:它清晰且非常紧凑。不错。
【解决方案2】:

这是一个函数式方法的草图。这有点神秘。实际上,我可能会使用您的方法(使用 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
>>>

不是很优雅。同样,我会采用命令式解决方案。不过,也许有人有更优雅的功能解决方案。

【讨论】:

    【解决方案3】:

    您的代码在我看来很好:它易于阅读和理解。我只是删除一些重复,使其看起来像:

    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
    

    【讨论】:

    • 我会说这是最Pythonic的方式。
    猜你喜欢
    • 2021-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多