LINQ挑战管理范围 [英] Managing ranges with LINQ challenge

查看:78
本文介绍了LINQ挑战管理范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出以下数字(代表星期几):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 ifed 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆