相当于Ruby的chunk_while的Python吗?

时间:2018-10-09 14:01:16

标签: python grouping

我想在Ruby代码中使用一些有趣的用例,并将它们转换为Python。我认为我们可以在任何lib中使用,我主要使用pandas和numpy。

例如,假设您有一个定时事件数组,这些事件有一个时间戳和另一个属性(一个对象或一个元组)。

我想要一个组列表/数组,其中这些组是“连续的”事件,其宽限期为g个单位(在这种情况下为时间单位)。

在我的Ruby代码中,我使用类似这样的内容:

grouped_events = events.chunk_while do |previous_event, next_event|
   next_event.timestamp <= previous_event.timestamp + grace_period
end

由于我不仅在定时事件中使用了我可以排序的东西(所以它们在某种程度上是可比的),所以我问:有一种通用的方法,或者是已知的lib可以做到这一点?

2 个答案:

答案 0 :(得分:2)

Python没有等效功能。您必须自己编写。

这是我的实现,使用iteratoryield statement

def chunk_while(iterable, predicate):
    itr = iter(iterable)

    try:
        prev_value = next(itr)
    except StopIteration:
        # if the iterable is empty, yield nothing
        return

    chunk = [prev_value]
    for value in itr:
        # if the predicate returns False, start a new chunk
        if not predicate(prev_value, value):
            yield chunk
            chunk = []

        chunk.append(value)
        prev_value = value

    # don't forget to yield the final chunk
    if chunk:
        yield chunk

可以像这样使用:

>>> list(chunk_while([1, 3, 2, 5, 5], lambda prev, next_: next_ <= prev + 2))
[[1, 3, 2], [5, 5]]

答案 1 :(得分:1)

我不知道有一个现成的解决方案,但是从头开始编写一个解决方案并不难。遍历序列的元素,根据您的条件测试每对项目,然后选择是将其添加到现有组中还是创建新组。

import collections

def pairs(seq):
    """yields (previous, current) pairs from the given iterable."""
    no_item = object()
    previous = no_item
    for item in seq:
        if previous is not no_item:
            yield (previous, item)
        previous = item

def chunk_contiguous(seq, criteria):
    cur_group = []
    for previous, current in pairs(seq):
        if criteria(previous, current):
            cur_group.append(current)
        else:
            yield cur_group
            cur_group = [current]
    if cur_group: 
        yield cur_group

Event = collections.namedtuple("Event", ["name", "timestamp"])

events = [
    Event("foo", 0),
    Event("bar", 1),
    Event("baz", 10),
    Event("qux", 12),
    Event("Larry", 17),
    Event("Curly", 21),
    Event("Moe", 25),

]

g = 4

for group in chunk_contiguous(events, lambda previous, current: current.timestamp <= previous.timestamp + g):
    print(group)

结果:

[Event(name='bar', timestamp=1)]
[Event(name='baz', timestamp=10), Event(name='qux', timestamp=12)]
[Event(name='Larry', timestamp=17), Event(name='Curly', timestamp=21), Event(name='Moe', timestamp=25)]