LINQ挑战管理范围 [英] Managing ranges with LINQ challenge
问题描述
给出以下数字(代表星期几):1,2,3,4,5,6,7
.
Given the following numbers (representing days of week): 1,2,3,4,5,6,7
.
以下是一些组合示例及其所需的输出:
Here are some combination examples and their desired output:
-
1,2,3,5,6,7
->1-3,5-7
-
1,3,5,7
->1,3,5,7
-
1,2,5,6
->1,2,5,6
-
1,2,3,6,7
->1-3,6,7
1,2,3,5,6,7
->1-3,5-7
1,3,5,7
->1,3,5,7
1,2,5,6
->1,2,5,6
1,2,3,6,7
->1-3,6,7
这个想法是连续3天或更多天成为一个范围,而将单日或非后续天分别绘制(或者最好将范围从2开始).
The idea is that 3 or more consecutive days become a range while single or non-following days are rendered separately (or is it nicer to make range starting from 2).
我不知道应该从哪里开始写一个复杂的if
ed函数,或者可以使用LINQ函数之一来完成?
有什么多汁的建议吗?
I don't know where to start should I write a complicated if
ed function or this can be done with one of the LINQ functions?
Any juicy suggestions?
我使用数字来简化范围的概念,但是在我的代码中,我声明了一个标记的枚举,如下所示:
I used numbers to simplify the idea of ranges, but in my code I have an flagged enum declared as follows:
[Flags]
public enum DaysOfWeek
{
Sunday = 0x1,
Monday = 0x2,
Tuesday = 0x4,
Wednesday = 0x8,
Thursday = 0x10,
Friday = 0x20,
Saturday = 0x40
}
我有一个实体OpeningTimes
,其域为DaysOfWeek
,该字段指示该实体的小时范围(在另一个属性中定义)在一周中的哪几天适用.
I have an entity OpeningTimes
with a field DaysOfWeek
, that tells what days in week the hour-ranges (defined in another property) of this entity apply to.
因此获得我使用的上述内容(要真正获得我将使用索引+ 1添加Select
的数字):
So the get the above I use (to really get numbers I'd add Select
using index + 1):
var days = Enum.GetValues(typeof(DaysOfWeek))
.Cast<DaysOfWeek>()
.Where(dow => Model.DaysOfWeek.HasFlag(dow));
我认为这个想法是先删除一个范围内的数字.
I think the idea is to first remove the numbers within a range.
我相信我正在寻找一种聚合函数,该函数也可以接收先前的值,并且可以返回另一个值类型,因此我可以将其设为当前值-1等于prev的函数.值,我等待下一个值,直到range不连续(或者如果element代表自身)为止,这是我让最后一个批量作为匿名对象返回并开始处理新值的时候.
I believe I'm looking for an aggregation function that receives the previous value as well, and can return another value-type, so I can make a function that if current value -1 equals prev. value, I wait for the next value, until range is not consecutive (or if element stands for itself) which is when I yield return the last bulk as an anonymous object and start working on the new one.
然后,我将创建一个格式为if (item.First != item.Last) string.Join("-", item.First, Item.Last);
Then I'll make a formatting function that says if (item.First != item.Last) string.Join("-", item.First, Item.Last);
推荐答案
有趣的问题.为了提高可读性,我决定使用一个代表范围的类:
Interesting problem. I decided for readability to have a class representing a range:
class NumberRange
{
public int Start { get; set;}
public int End { get; set;}
public override string ToString()
{
return Start == End ? Start.ToString() : String.Format("{0}-{1}",Start,End);
}
}
和一种扩展方法,可将有序整数的IEnumerable转换为范围的IEnumerable:
and an extension method to turn an IEnumerable of ordered integers into an IEnumerable of ranges:
public static IEnumerable<NumberRange> ToRanges(this IEnumerable<int> numbers)
{
NumberRange currentRange = null;
foreach(var number in numbers)
{
if (currentRange == null)
currentRange = new NumberRange() { Start = number, End = number };
else if (number == currentRange.End + 1)
currentRange.End = number;
else
{
yield return currentRange;
currentRange = new NumberRange { Start = number, End = number };
}
}
if (currentRange != null)
{
yield return currentRange;
}
}
有了它,就可以获取范围并根据需要设置其格式:
And with that in place you can get the ranges and format them however you want:
String.Join(",",
new int[] { 1,2,3,5,7,8,9,11 }
.ToRanges()
.Select(r => r.ToString()))
这篇关于LINQ挑战管理范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!