我有一个字典,它存储了一周中的每一天以及当天的开放/关闭时间。
Dictionary<string, string> hours = new Dictionary<string, string>();
hours.Add("M", String.Format("{0}-{1}", this.MondayOpen, this.MondayClosed));
hours.Add("T", String.Format("{0}-{1}", this.TuesdayOpen, this.TuesdayClosed));
hours.Add("W", String.Format("{0}-{1}", this.WednesdayOpen, this.WednesdayClosed));
hours.Add("Th", String.Format("{0}-{1}", this.ThursdayOpen, this.ThursdayClosed));
hours.Add("F", String.Format("{0}-{1}", this.FridayOpen, this.FridayClosed));
hours.Add("S", String.Format("{0}-{1}", this.SaturdayOpen, this.SaturdayClosed));
hours.Add("Su", String.Format("{0}-{1}", this.SundayOpen, this.SundayClosed));
我希望能够遍历字典并根据相似的时间对日期进行分组。例如,我想这样显示数据
M-Th 8:00 AM - 4:00 PM
F 8:00 AM - 6:00 PM
(leave Saturday and Sunday off if those days don't have open/close times)
我试过几种不同的方法,但都没能完全正确。这是我最近的一次尝试。
private string FormatHours2()
{
StringBuilder sb = new StringBuilder();
// add all of the hours to a dictionary
Dictionary<string, string> hours = new Dictionary<string, string>();
hours.Add("M", String.Format("{0}-{1}", this.MondayOpen, this.MondayClosed));
hours.Add("T", String.Format("{0}-{1}", this.TuesdayOpen, this.TuesdayClosed));
hours.Add("W", String.Format("{0}-{1}", this.WednesdayOpen, this.WednesdayClosed));
hours.Add("Th", String.Format("{0}-{1}", this.ThursdayOpen, this.ThursdayClosed));
hours.Add("F", String.Format("{0}-{1}", this.FridayOpen, this.FridayClosed));
hours.Add("S", String.Format("{0}-{1}", this.SaturdayOpen, this.SaturdayClosed));
hours.Add("Su", String.Format("{0}-{1}", this.SundayOpen, this.SundayClosed));
// placeholder for the previous time range
string prevValue = String.Empty;
// inrun - indicates whether we are in a run of the same times.
// firstTime - indicates whether this is the first time through the loop.
bool inrun = false, firstTime = true;
for (int i = 0; i < hours.Count; i++)
{
KeyValuePair<string, string> entry = hours.ElementAt(i);
if (entry.Value != prevValue)
{
if (firstTime)
{
if (HasValue(entry.Value)) { sb.Append(entry.Key); }
}
else
{
if (!inrun)
{
if (HasValue(prevValue)) { sb.Append(String.Format(" {0},", hours.ElementAt(i - 1).Value)); }
if (HasValue(entry.Value)) { sb.Append(entry.Key); }
}
else
{
if (HasValue(prevValue))
{
sb.Append(String.Format("-{0} {1}", hours.ElementAt(i - 1).Key, hours.ElementAt(i - 1).Value));
}
if (HasValue(entry.Value)) { sb.Append(String.Format(",{0}", entry.Key)); }
}
}
inrun = false;
}
else
{
inrun = true;
}
firstTime = false;
prevValue = entry.Value;
// if we're on the last iteration, write the value
if (i == hours.Count() - 1)
{
if (inrun)
{
if (HasValue(entry.Value))
{
sb.Append(String.Format("-{0} {1}", entry.Key, entry.Value));
}
}
else
{
if (HasValue(prevValue))
{
sb.Append(String.Format(" {0}", hours.ElementAt(i - 1).Value));
}
}
}
}
return sb.ToString().TrimEnd(',');
}
这在所有情况下都很有效,除了在一周的中间几天关闭时,它不加逗号。
非常感谢任何帮助。如果有人知道更好的方法,我愿意接受建议。我甚至不需要用字典。
谢谢
你的代码很难阅读和维护,因为你试图同时做两件事:压缩数据(按相同的小时将天数合并成组)和用描述构建文本。
我会把这分成两个步骤,添加一些LINQ并重新组织一下。让我们从压缩问题开始。我们想要的是将列表分成具有相同工作时间的更小的集群。不幸的是,没有内置的LINQ方法来解决这个问题。当然我们也可以写一个:
public static class EnumerableExtensions
{
public static IEnumerable<TResult> Compact<T, TKey, TResult>(
this IEnumerable<T> source,
Func<T,TKey> keySelector,
Func<TKey, IEnumerable<T>, TResult> resultSelector)
{
if (!source.Any())
yield break;
var comparer = EqualityComparer<TKey>.Default;
TKey previousKey = keySelector(source.First());
List<T> group = new List<T>() { source.First() };
foreach (var item in source.Skip(1))
{
TKey currentKey = keySelector(item);
if (!comparer.Equals(previousKey, currentKey))
{
yield return resultSelector(previousKey, group);
group = new List<T>();
}
group.Add(item);
previousKey = currentKey;
}
if (group.Any())
{
yield return resultSelector(previousKey, group);
}
}
}
这段代码应该放在某个helper库中,这样就不会被查看代码的程序员看到。有了这个有用的方法,我们可以使用它:
var compact = hours.Compact(p => p.Value,
(key, values) => new {
Hours = key,
Start = values.First().Key,
End = values.Last().Key
});
字典现在已经被压缩了(相对于KeyValuePair<>.Value
,意思是工作时间),匿名对象的集合现在有了关于天的所有必要信息,你可以简单地用适当的格式string.Join
它们:
Func<string, string, string> dayFormatter =
(first, second) => first == second ? first : string.Format("{0} - {1}", first, second);
var result = string.Join(", ", compact.Select(x => string.Format("{0} {1}",
dayFormatter(x.Start, x.End),
x.Hours)));
注:对于示例数据,如:
string MondayOpen = "8:00 AM"; string MondayClosed = "4:00 PM";
string TuesdayOpen = "8:00 AM"; string TuesdayClosed = "4:00 PM";
string WednesdayOpen = "7:00 AM"; string WednesdayClosed = "3:00 PM";
string ThursdayOpen = "8:00 AM"; string ThursdayClosed = "4:00 PM";
string FridayOpen = "8:00 AM"; string FridayClosed = "4:00 PM";
string SaturdayOpen = "8:00 AM"; string SaturdayClosed = "2:00 PM";
string SundayOpen = "8:00 AM"; string SundayClosed = "2:00 PM";
Dictionary<string, string> hours = new Dictionary<string, string>();
hours.Add("M", String.Format("{0}-{1}", MondayOpen, MondayClosed));
hours.Add("T", String.Format("{0}-{1}", TuesdayOpen, TuesdayClosed));
hours.Add("W", String.Format("{0}-{1}", WednesdayOpen, WednesdayClosed));
hours.Add("Th", String.Format("{0}-{1}", ThursdayOpen, ThursdayClosed));
hours.Add("F", String.Format("{0}-{1}", FridayOpen, FridayClosed));
hours.Add("S", String.Format("{0}-{1}", SaturdayOpen, SaturdayClosed));
hours.Add("Su", String.Format("{0}-{1}", SundayOpen, SundayClosed));
上面的代码产生:
`"M - T 8:00 AM-4:00 PM, W 7:00 AM-3:00 PM, Th - F 8:00 AM-4:00 PM, S - Su 8:00 AM-2:00 PM"`