我得到了一周中的一天。我想做的Python代码:
def week_days_to_string(week_days):
"""
>>> week_days_to_string(('Sunday', 'Monday', 'Tuesday'))
'Sunday to Tuesday'
>>> week_days_to_string(('Monday', 'Wednesday'))
'Monday and Wednesday'
>>> week_days_to_string(('Sunday', 'Wednesday', 'Thursday'))
'Sunday, Wednesday, Thursday'
"""
if len(week_days) == 2:
return '%s and %s' % weekdays
elif week_days_consecutive(week_days):
return '%s to %s' % (week_days[0], week_days[-1])
return ', '.join(week_days)
我只需要week_days_consecutive
功能(难点嘿)。
我是如何做到这一点的?
澄清:
我的措辞和例子引起了一些混乱。我不仅希望将此功能限制在工作周。我想考虑一周中的所有日子(S,M,T,W,T,F)。我很抱歉昨晚不清楚这一点。编辑了问题的正文,使其更加清晰。
编辑:向其投掷一些扳手
环绕顺序:
>>> week_days_to_string(('Sunday', 'Monday', 'Tuesday', 'Saturday'))
'Saturday to Tuesday'
并且,根据@ user470379和可选:
>>> week_days_to_string(('Monday, 'Wednesday', 'Thursday', 'Friday'))
'Monday, Wednesday to Friday'
答案 0 :(得分:5)
我会通过以下方式解决这个问题:
以下是使用calendar.day_name
,range
和其中一些进行理解的方法:
day_indexes = {name:i for i, name in enumerate(calendar.day_name)}
def weekdays_consecutive(days):
indexes = [day_indexes[d] for d in days]
expected = range(indexes[0], indexes[-1] + 1)
return indexes == expected
其他一些选项,取决于您的需求:
如果你需要Python< 2.7,而不是字典理解,你可以使用:
day_indexes = dict((name, i) for i, name in enumerate(calendar.day_name))
如果您不想允许星期六和星期日,请在最后两天修剪:
day_indexes = ... calendar.day_name[:-2] ...
如果您需要在星期日之后回首,那么最简单的方法就是检查每个项目是否比上一个项目多一个,但是在模7中工作:
def weekdays_consecutive(days):
indexes = [day_indexes[d] for d in days]
return all(indexes[i + 1] % 7 == (indexes[i] + 1) % 7
for i in range(len(indexes) - 1))
更新:对于扩展问题,我仍然坚持使用日期索引dict,但我会:
这是执行此操作的代码:
def weekdays_to_string(days):
# convert days to indexes
day_indexes = {name:i for i, name in enumerate(calendar.day_name)}
indexes = [day_indexes[d] for d in days]
# find the places where sequential days end
ends = [i + 1
for i in range(len(indexes))
if (indexes[(i + 1) % len(indexes)]) % 7 !=
(indexes[(i) % len(indexes)] + 1) % 7]
# wrap the days if necessary to get longest possible sequences
split = ends[-1]
if split != len(days):
days = days[split:] + days[:split]
ends = [len(days) - split + end for end in ends]
# group the days in sequential spans
spans = [days[begin:end] for begin, end in zip([0] + ends, ends)]
# format as requested, with "to", "and", commas, etc.
words = []
for span in spans:
if len(span) < 3:
words.extend(span)
else:
words.append("%s to %s" % (span[0], span[-1]))
if len(days) == 1:
return words[0]
elif len(days) == 2:
return "%s and %s" % tuple(words)
else:
return ", ".join(words)
您也可以尝试使用以下代码而不是最后一个if/elif/else
块来获取最后两个项目之间的“和”以及其他所有内容之间的逗号:
if len(words) == 1:
return words[0]
else:
return "%s and %s" % (", ".join(words[:-1]), words[-1])
这与规格略有不同,但在我看来更漂亮。
答案 1 :(得分:2)
def weekdays_consecutive(inp):
days = { 'Monday': 0,
'Tuesday': 1,
'Wednesday': 2,
'Thursday': 3,
'Friday': 4 }
return [days[x] for x in inp] == range(days[inp[0]], days[inp[-1]] + 1)
由于您已经检查了其他情况,我认为这样就足够了。
答案 2 :(得分:1)
这是我的完整解决方案,您可以随意使用它; (该代码已被置于公共领域,但如果您或您的计算机因使用该代码而发生任何事情,我将不承担任何责任,并且不保证yadda yadda ya)。
week_days = {
'monday':0,
'tuesday':1,
'wednesday':2,
'thursday':3,
'friday':4,
'saturday':5,
'sunday':6
}
week_days_reverse = dict(zip(week_days.values(), week_days.keys()))
def days_str_to_int(days):
'''
Converts a list of days into a list of day numbers.
It is case ignorant.
['Monday', 'tuesday'] -> [0, 1]
'''
return map(lambda day: week_days[day.lower()], days)
def day_int_to_str(day):
'''
Converts a day number into a string.
0 -> 'Monday' etc
'''
return week_days_reverse[day].capitalize()
def consecutive(days):
'''
Returns the number of consecutive days after the first given a sequence of
day numbers.
[0, 1, 2, 5] -> 2
[6, 0, 1] -> 2
'''
j = days[0]
n = 0
for i in days[1:]:
j = (j + 1) % 7
if j != i:
break
n += 1
return n
def days_to_ranges(days):
'''
Turns a sequence of day numbers into a list of ranges.
The days can be in any order
(n, m) means n to m
(n,) means just n
[0, 1, 2] -> [(0, 2)]
[0, 1, 2, 4, 6] -> [(0, 2), (4,), (6,)]
'''
days = sorted(set(days))
while days:
n = consecutive(days)
if n == 0:
yield (days[0],)
else:
assert n < 7
yield days[0], days[n]
days = days[n+1:]
def wrap_ranges(ranges):
'''
Given a list of ranges in sequential order, this function will modify it in
place if the first and last range can be put together.
[(0, 3), (4,), (6,)] -> [(6, 3), (4,)]
'''
if len(ranges) > 1:
if ranges[0][0] == 0 and ranges[-1][-1] == 6:
ranges[0] = ranges[-1][0], ranges[0][-1]
del ranges[-1]
def range_to_str(r):
'''
Converts a single range into a string.
(0, 2) -> "Monday to Wednesday"
'''
if len(r) == 1:
return day_int_to_str(r[0])
if r[1] == (r[0] + 1) % 7:
return day_int_to_str(r[0]) + ', ' + day_int_to_str(r[1])
return day_int_to_str(r[0]) + ' to ' + day_int_to_str(r[1])
def ranges_to_str(ranges):
'''
Converts a list of ranges into a string.
[(0, 2), (4, 5)] -> "Monday to Wednesday, Friday, Saturday"
'''
if len(ranges) == 1 and ranges[0] == (0, 6):
return 'all week'
return ', '.join(map(range_to_str, ranges))
def week_days_to_string(days):
'''
Converts a list of days in string form to a stringed list of ranges.
['saturday', 'monday', 'wednesday', 'friday', 'sunday'] ->
'Friday to Monday, Wednesday'
'''
ranges = list(days_to_ranges(days_str_to_int(days)))
wrap_ranges(ranges)
return ranges_to_str(ranges)
功能强>
如果您发现任何问题,请添加评论,我会尽力解决。
答案 3 :(得分:0)
您必须检查给定的第一个日期,然后列出包含所有工作日的列表,检查下一个给定日期是否在列表中的下一个索引处,然后重复。
假设给定的天数有序,可以通过几个循环轻松完成。
答案 4 :(得分:0)
这要么采取一些错综复杂的逐案逻辑,要么按顺序进行所有日期的硬编码存储。我更喜欢后者。
def weekdays_consecutive(x):
allDays = { 'Monday':1, 'Tuesday':2, 'Wednesday':3, 'Thursday':4, 'Friday':5, 'Saturday' : 6, 'Sunday' : 7}
mostRecent = x[0]
for i in x[1:]:
if allDays[i] % 7 != allDays[mostRecent] % 7 + 1: return False
mostRecent = i
return True
这可以对输入进行排序:x.sort(lambda x, y: allDays[x] - allDays[y])
。我不知道您希望在
>>>x = ['Tuesday', 'Thursday', 'Monday', 'Friday']
>>>x.sort(lambda x, y: allDays[x] - allDays[y])
>>>x
['Monday', 'Tuesday', 'Thursday', 'Friday']
这取决于没有非天存在。我想你想在weekdays_to_string函数中处理这个问题,而不是在weekdays_consecutive中处理这个问题。
我还认为您希望将其他功能的第一种情况更改为“和”而不是“更改”,并为单日输入添加大小写。
编辑:我刚刚修好了一个非常愚蠢的错误,现在应该工作了!答案 5 :(得分:0)
我没有测试我必须说。
def test(days):
days = list(days)
if len(days) == 1:
return days[0]
elif len(days) == 2:
return ' to '.join(days)
else:
return ''.join(days[:1] + [' to ' + days[-1]])
答案 6 :(得分:-1)
import itertools
#probably a better way to obtain this like with the datetime library
WEEKDAYS = (('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'))
def weekdays_consecutive(days):
#assumes that days only contains valid weekdays
if len(days) == 0:
return True #or False?
iter = itertools.cycle(WEEKDAYS)
while iter.next() != days[0]: pass
for day in days[1:]:
if day != iter.next(): return False
return True
#...
>>> weekdays_consecutive(('Friday', 'Monday'))
True
>>> weekdays_consecutive(('Friday', 'Monday', 'Tuesday'))
True
>>> weekdays_consecutive(('Friday', 'Monday', 'Tuesday', 'Thursday'))
False