用户可以从列表中选择任意数量的工作日。算法应找到所选天数的最长连续组。如果小组跨越两周,则开始日期可以在结束日之后。如果它更简单,则只需要检测至少3天的一组。越过周边界,这最多允许一组。 (一周内没有两组没有连接的3天。)
例如,如果用户从列表中选择星期一,星期二,星期三和星期六,则显示应为“星期一 - 星期三和星期六”。
另一个例子是:周三,周五,周六,周日,周一 - > “星期三,星期五,星期五”。
是否有一种有效的算法,最好用C#或类似的语言?我的C#hackwork现在已超过一页(包括几条评论),但仍未完成。
答案 0 :(得分:2)
使用this answer,稍作修改:
使用dtb GroupAdjacentBy
的修改版本,该版本接受minCount
作为参数:
public static IEnumerable<IEnumerable<T>> GroupAdjacentBy<T>(
this IEnumerable<T> source, Func<T, T, bool> predicate, int minCount)
{
using (var e = source.GetEnumerator())
{
if (e.MoveNext())
{
var list = new List<T> { e.Current };
var pred = e.Current;
while (e.MoveNext())
{
// if adjacent, add to list
if (predicate(pred, e.Current))
{
list.Add(e.Current);
}
else
{
// otherwise return previous elements:
// if less than minCount elements,
// return each element separately
if (list.Count < minCount)
{
foreach (var i in list)
yield return new List<T> { i };
}
else
{
// otherwise return entire group
yield return list;
}
// create next group
list = new List<T> { e.Current };
}
pred = e.Current;
}
yield return list;
}
}
}
并将GroupAdjacentBy
的条件更改为按周转换分组:
// week starts with Monday, so this should
// represent: Wed, Fri, Sat, Sun, Mon
int[] array = new int[] { 1, 2, 4, 5, 6, 0 };
Func<int, int, bool> adjacentCriteria = (x, y) => (x+1==y) || (x==6 && y==0);
string result = string.Join(", ", array
.GroupAdjacentBy(adjacentCriteria, 3)
.Select(g => new int[] { g.First(), g.Last() }.Distinct())
.Select(g => string.Join("-", g)));
Console.WriteLine(result); // output: 1, 2, 4-0
答案 1 :(得分:0)
我已经完成了我的版本。它比另一个稍长,但它再次处理文本表示并完成此任务。怎么样?
using System;
using System.Text;
namespace WeekMathTest
{
class Program
{
static void Main(string[] args)
{
string[] weekDayNames = new string[] {
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat",
"Sun"
};
WeekDays weekDays = WeekDays.Monday | WeekDays.Tuesday | WeekDays.Thursday | WeekDays.Saturday | WeekDays.Sunday;
Console.WriteLine(WeekDayGroup(weekDays, weekDayNames));
}
static string WeekDayGroup(WeekDays weekDays, string[] weekDayNames)
{
int groupStart = 0, groupEnd = 0, groupLength = 0;
int maxGroupStart = 0, maxGroupEnd = 0, maxGroupLength = 0;
// Iterate all days in a repeated range
// (Sat/Sun doesn't need to be repeated or it would be in the first group)
for (int day = 1; day <= 7 + 5; day++)
{
// Is this day set?
int bitValue = 1 << ((day - 1) % 7);
bool daySet = ((int) weekDays & bitValue) != 0;
if (daySet)
{
if (groupStart == 0)
{
// First day set, remember it as group start
groupStart = day;
groupEnd = day;
groupLength = 1;
}
else
{
// Group has already been started, set new end
groupEnd = day;
groupLength = groupEnd - groupStart + 1;
if (groupLength == 7)
{
// Seen every day of the week, stop here
break;
}
}
}
else
{
if (groupLength >= 3 && groupLength > maxGroupLength)
{
// Group was long enough and longer than the last one, save it
maxGroupStart = groupStart;
maxGroupEnd = groupEnd;
maxGroupLength = groupLength;
}
// Reset operation variables
groupStart = 0;
groupEnd = 0;
groupLength = 0;
}
}
// Final check
if (groupLength >= 3 && groupLength > maxGroupLength)
{
// Group was long enough and longer than the last one, save it
maxGroupStart = groupStart;
maxGroupEnd = groupEnd;
maxGroupLength = groupLength;
}
// Clear all group days from the original value
for (int day = maxGroupStart; day <= maxGroupEnd; day++)
{
int bitValue = 1 << ((day - 1) % 7);
weekDays = (WeekDays) ((int) weekDays & ~bitValue);
}
// Generate output string
StringBuilder sb = new StringBuilder();
for (int day = 1; day <= 7; day++)
{
int bitValue = 1 << ((day - 1) % 7);
bool daySet = ((int) weekDays & bitValue) != 0;
if (daySet)
{
if (sb.Length > 0) sb.Append(", ");
sb.Append(weekDayNames[day - 1]);
}
else if (day == maxGroupStart)
{
if (sb.Length > 0) sb.Append(", ");
sb.Append(weekDayNames[day - 1]);
sb.Append("-");
sb.Append(weekDayNames[(maxGroupEnd - 1) % 7]);
}
}
return sb.ToString();
}
[Flags]
enum WeekDays
{
Monday = 1,
Tuesday = 2,
Wednesday = 4,
Thursday = 8,
Friday = 16,
Saturday = 32,
Sunday = 64
}
}
}