首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >连续几天将工作时间分组

连续几天将工作时间分组
EN

Code Review用户
提问于 2017-09-08 18:39:18
回答 2查看 396关注 0票数 5

问题描述

问题最初发布在这里:用Python解析和清理存储时间的文本块

给定以下多行字符串:

代码语言:javascript
复制
"""Hours
Monday 9:30 AM - 9:00 PM
Tuesday 9:30 AM - 9:00 PM
Wednesday 9:30 AM - 9:00 PM
Thursday 9:30 AM - 9:00 PM
Friday 9:30 AM - 11:00 PM
Saturday 9:30 AM - 11:00 PM
Sunday 11:00 AM - 6:00 PM
Holiday Hours
Thanksgiving Day 11:00 AM - 6:00 PM"""

将连续工作日按工作时间分组,产生以下输出:

代码语言:javascript
复制
"""Mon-Thu 9:30AM-9:00PM  
Fri-Sat 9:30AM-11:00PM
Sun & Hol 11:00AM-6:00PM"""

溶液

我的方法基于解析工作日的行,按照第一个空格拆分,然后使用itertools.groupby()对每一行的第二项进行排序,使用groupby的S实现细节--它只将连续的匹配组合在一起:

代码语言:javascript
复制
from itertools import groupby
from operator import itemgetter


data = """Hours
Monday 9:30 AM - 9:00 PM
Tuesday 9:30 AM - 9:00 PM
Wednesday 9:30 AM - 9:00 PM
Thursday 9:30 AM - 9:00 PM
Friday 9:30 AM - 11:00 PM
Saturday 9:30 AM - 11:00 PM
Sunday 11:00 AM - 6:00 PM
Holiday Hours
Thanksgiving Day 11:00 AM - 6:00 PM"""

# filter relevant rows with weekdays only
rows = [row.split(" ", 1) for row in data.splitlines()[1:-2]]

# group consecutive days by a time range
result = []
for time_range, group in groupby(rows, key=itemgetter(1)):
    days_in_group = [item[0] for item in group]

    first_day, last_day = days_in_group[0][:3], days_in_group[-1][:3]
    range_end = "-" + str(last_day) if first_day != last_day else ""

    result.append("{begin}{end} {time_range}".format(begin=first_day,
                                                     end=range_end,
                                                     time_range=time_range))

print("\n".join(result))

这是解决这个问题的最优方案吗?是毕多尼吗?在代码质量方面,您会改进什么?

EN

回答 2

Code Review用户

回答已采纳

发布于 2017-09-09 00:06:55

在输出中获得& Hol很难以任何合理的方式以编程的方式实现,没有硬编码的特殊情况。我看你并没有试图满足这部分要求。因此,规范是开放的解释。我要说的是,一个合理的方法是,如果这条线看起来像一周中的一天,就尝试解析它的开放时间,如果该行包含其他内容,则通过输出。

对于解析,我将使用正则表达式。如果使用命名捕获组,可以避免神秘的表达式,如.split()itemgetter(1)days_in_group[0][:3]

而不是.append(),我把它写成一个生成器函数。

代码语言:javascript
复制
from itertools import groupby
from operator import itemgetter
import re

def group_by_hours(s):
    REGEX = re.compile(r'^(?P<day_abbrev>\w{3})\w*day (?P<hours>.* - .*)|'
                       r'^(?P<misc>.*)', re.MULTILINE)
    for hours, lines in groupby(REGEX.finditer(s), itemgetter('hours')):
        lines = list(lines)
        if not hours:
            for line in lines:
                yield line['misc']
        elif len(lines) == 1:
            yield "{0} {1}".format(lines[0]['day_abbrev'], hours)
        elif len(lines) > 1:
            yield "{0}-{1} {2}".format(lines[0]['day_abbrev'],
                                       lines[-1]['day_abbrev'],
                                       hours)

print('\n'.join(group_by_hours(data)))
票数 1
EN

Code Review用户

发布于 2017-09-08 22:27:07

幻数

在……里面

代码语言:javascript
复制
rows = [row.split(" ", 1) for row in data.splitlines()[1:-2]]

1和-2的魔术数字有点麻烦。也许你想要创建一个发电机,它知道如何抑制“小时”,并且在“假日时间”之后不会产生更多的行。

另外,

代码语言:javascript
复制
first_day, last_day = days_in_group[0][:3], days_in_group[-1][:3]

有一些神奇的数字,但可以说它们更有意义。您可以使用yield day[:3], time_range让您的生成器负责日解析。

变量重命名

在字符串格式中,您选择将first_day重命名为begin,将range_end重命名为end。我想我的建议是“不要那样做”。或者,如果您喜欢这些变量的名称,请始终使用该名称。

在……里面

代码语言:javascript
复制
days_in_group = [item[0] for item in group]

标识符item有点模糊。pair会更好(如果您倾向于冗长的话,也可能是day_range )。

全局范围

您使用rows和其他标识符污染了顶级命名空间。您的文件不能通过import重用。请使用

代码语言:javascript
复制
if __name__ == '__main__':

成语是将这些代码行隐藏在def main():或类似的代码下面。

总体来说,是的,这是明智的代码,合二为一,合二为一。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/175156

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档