【问题标题】:How to match a list of dates to a pattern?如何将日期列表与模式匹配?
【发布时间】:2013-11-09 11:24:51
【问题描述】:

我有一个 Python listtuples,其中包含三个对象:string(例如:标题)、date 和另一个 string(例如:名称)。

示例:

scientific_works = [
    ('SW 1', datetime.date(2000, 10, 15), 'auth 1'),
    ('SW 2', datetime.date(2000, 11, 3), 'auth 1'),
    ('SW 3', datetime.date(2000, 11, 4), 'auth 1'),
    ('SW 4', datetime.date(2000, 12, 1), 'auth 1'),
]

那么我有一个模式:

datedate,(至少)int 项目从listint 天/周/月/年

例子:

from  datetime.date(2000, 11, 1)
until datetime.date(2000, 11, 30)
1 item per day

我希望算法做什么:

  • 鉴于该列表和该模式,过滤后的项目是否符合规则?

在示例的情况下,此模式将匹配 2 个项目,它们都与此处的规则匹配:1 item complete per day,但是,由于没有 an item 用于每个日期块,因此算法将返回 false .

另一个例子:

  • 每个 Int_2(天/周/月)是否有(至少)Int_1 数量的项目(作品)?
    • 每天 1 个工作意味着在给定的日期范围内,每 1 天块至少有 1 个项目。每周 2 件作品意味着,日期范围内每周(或 7 天块)至少 2 件作品。

当然,我可以遍历列表并找出哪些项目与 fromuntil 模式匹配。

但是,我真的很困惑将它们与其余规则匹配以查看它是正匹配还是负匹配。

我的问题:

  • 如何构建算法,为其提供列表和规则模式(每天或每周或每月或每年 x 项),并查看它是否匹配?

我正在为一个应用程序开发一个小组件,其中给定了特定的数据(列表)和规则(模式),如果作者解锁了奖励。

我已经完成了 udacity 的几个 Python 课程,包括大多数算法,但真的找不到解决办法。

到目前为止,我想到了这个:

  1. 过滤具有给定日期范围的列表项。
  2. 计算范围内的范围块:从 d1 到 d2 的 1 天 = 5 天 - 从 d1 到 d2 的 1 周 = 3 周
  3. 在上面计算的int 范围内创建一个循环。
  4. 在循环的每个步骤中将周、月、年转换为天。
  5. 将金额添加到开始日期并查看项目是否与日期范围匹配。
  6. 将金额添加到日期范围的下一个开始并重复。

但是,这不起作用,我认为将块转换为天根本没有效率。

谢谢。

【问题讨论】:

  • 现在回到stackoverflow上最常见的问题。你试过什么?
  • @alKid,感谢您的评论。我实现了日期范围的第一次过滤。其余的,我在纸上画了模式,并试图想出一个过程(算法),但我失败了,因为我不知道从哪里开始。
  • 时间段的开始日期或日历日期何时开始?例如,[date(2000, 6, 15), date(2001, 1, 1)] 列表是否匹配模式:from datetime.date(2000, 6, 14) until datetime.date(2001, 6, 1) 2 item per year
  • 结束日期和开始日期是否包括在内都没有关系。基本上,该算法是看,比如说,一位科学家,是否在从 - 到日期之间每月发表一篇或更多论文,或者一个骑自行车的人是否每周练习一次,或者一个学生是否每天上学一次,持续 5 天。过滤的日期范围是最简单的,我已经介绍了,但其他部分——将模式匹配到列表真/假被证明是困难的。谢谢,非常感谢您的帮助!
  • @Phil:这与包容性无关。该列表包含两个不同的日历年 - 每年 一个 日期。但是当一年(如 两个 项。你看到矛盾了吗?您能否回答上一条评论中的问题:列表是否与模式匹配?

标签: python algorithm python-2.7 pattern-matching


【解决方案1】:

如果模式是:

从 start_date 直到 end_date 每期 X 项

然后要找出scientific_works 是否与模式匹配,可以使用numpy.histogram() function 的模拟:

import datetime
import numpy as np

ts = datetime.date.toordinal # or any monotonic numeric `date` function 
hist = np.histogram(map(ts, (date for title, date, name in scientific_works)),
                    bins=map(ts, daterange(start_date, end_date, period))[0]
does_it_match = all(x >= X for x in hist)

地点:

def daterange(start_date, end_date, period):
    d = start_date
    while d < end_date:
        yield d
        d += period

例子:

>>> from datetime import date, timedelta
>>> list(daterange(date(2000, 1, 1), date(2000, 2, 1), timedelta(days=7)))
[datetime.date(2000, 1, 1), datetime.date(2000, 1, 8),
 datetime.date(2000, 1, 15), datetime.date(2000, 1, 22),
 datetime.date(2000, 1, 29)]

【讨论】:

  • 由于我所有的测试用例都通过了,这些程序看起来确实有效。非常感谢你。如果你有机会,你能解释一下你是如何想出解决方案的吗?你是怎么想出来的,为什么会这样?我现在将阅读更多关于 numpy 的内容。谢谢。
  • @Phil:一旦我了解到您需要每个时期的项目数;很容易想出histogram(),它返回每个bin 的样本数。只需将date 转换为一个数字,您就得到了解决方案。顺便说一句,如果您在代码的其他部分不使用 numpy,那么您可以将 numpy.histogram() 替换为其类似物,例如,使用基于 itertools.groupby() 的东西。
【解决方案2】:

您能否发布一个更好的比赛规则示例?您是否在每个时间段内寻找特定数量的项目每位作者?或者您是否在一段时间内寻找某些条目,然后找到它们属于谁?这会影响排序。

我认为您最终将不得不对这些数据使用排序算法,如果您使用正确的方法,这并不可怕。

从您问题的底部,我认为如果您在每 n 个时间段(日/周/月)搜索 x 个项目,然后确定作者可能会有点混乱。如果您的作者数量有限,则可能更容易翻转它并为每个作者创建一个数组并将项目和日期存储在其中。然后,您只需对每个作者运行一个测试循环,检查他们的所有条目,看看它们是否符合要求。

对于 Python 课程,MIT OpenCourseware 的 6.00 Introduction to Computer Science and Programming 非常好。可以在http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-00-introduction-to-computer-science-and-programming-fall-2008/>

找到

【讨论】:

  • 你好@willianth。如果我的解释不够清楚,我很抱歉。感谢您有兴趣。如果您允许,我想详细说明:列表中的作者是多余的,它没有任何作用。给定一个列表,我想首先获取从 D1 到 D2 的项目,我可以做到。之后,我需要查看获得的列表是否与规则集匹配:每个 Int_2(天/周/月)是否有(至少)Int_1 数量的项目(作品)?例如:每天 1 件工作意味着给定日期范围内每 1 天块至少 1 个项目。每周 2 件作品意味着,日期范围内每周(或 7 天)至少 2 件作品。
  • @Phil:请不要将相关信息放在 cmets 中。 Update your question instead 其他人无需阅读页面上的所有内容即可看到它。
  • @J.F.Sebastian,已经这样做了 ;-) 虽然措辞可能有所不同,但我可能也会逐字添加这些内容。谢谢。
【解决方案3】:

我将使用以下设计:主生成器函数迭代一系列工作并产生“好”的工作;以及一组实现特定规则的可插入过滤器,例如日期范围、每天、每周、每月 N 项等。

下面是一个小例子来说明这个想法:

from datetime import date
from pprint import pprint

scientific_works = [
    ('SW 1', date(2000, 10, 15), 'auth 1'),
    ('SW 2', date(2000, 11, 3), 'auth 1'),
    ('SW 3', date(2000, 11, 4), 'auth 1'),
    ('SW 4', date(2000, 11, 5), 'auth 1'),
    ('SW 5', date(2000, 12, 1), 'auth 1'),
    ('SW 6', date(2000, 12, 15), 'auth 1'),
    ('SW 7', date(2000, 12, 18), 'auth 1'),
    ('SW 8', date(2000, 12, 22), 'auth 1'),
]

def filter_works(works, *filters):
    for work in works:
        good = True
        for fil in filters:
            good = good and fil(work)
        if good:
            yield work

class RangeFilter(object):
    def __init__(self, from_date, to_date):
        self.from_date = from_date
        self.to_date = to_date

    def __call__(self, work):
        return self.from_date <= work[1] <= self.to_date


class WorksPerMonthFilter(object):
    def __init__(self, limit):
        self.limit = limit
        self._current_month = date.min
        self._current_number = 0

    def __call__(self, work):
        month = date(work[1].year, work[1].month, 1)
        if month == self._current_month:
            self._current_number += 1
        else:
            self._current_month = month
            self._current_number = 1
        return self._current_number <= self.limit


if __name__ == '__main__':
    pprint(list(filter_works(scientific_works, RangeFilter(date(2000, 10, 1), date(2000, 11, 30)), WorksPerMonthFilter(2))))
    pprint(list(filter_works(scientific_works, RangeFilter(date(2000, 10, 1), date(2000, 12, 31)), WorksPerMonthFilter(2))))
    pprint(list(filter_works(scientific_works, RangeFilter(date(2000, 10, 1), date(2000, 12, 31)), WorksPerMonthFilter(3))))

【讨论】:

  • 你好@alexanderlukanin13。谢谢你的例子。它可以成为我实施过滤的起点。但是,让我感到困惑的部分是实施“如果它与模式匹配”,如从 x 到 y,每 Q 天/月/周是否有 Z 量的工作等。你认为我可以做些什么来验证?
  • 您是否要检查,例如,每月是否至少有 2 部作品?该算法将非常相似。您只需要在每个过滤器中存储整体状态(布尔值)。处理完序列后,您可以检查每个过滤器的状态,并通过和/或/您想要获得最终结果的任何逻辑组合它们。
  • 您可以将 filter_works 简化为return (work for work in works if all(fil(work) for fil in filters))
  • 请注意,all 不会执行 all 过滤器 - 它首先会停止 False
猜你喜欢
  • 2018-04-29
  • 1970-01-01
  • 2013-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多