.net C#将时间列表拆分为时间范围

z0qdvdin  于 2023-05-19  发布在  .NET
关注(0)|答案(7)|浏览(168)

我正在使用linq从整数列表中提取范围:
例如,我希望拆分以下列表:

List<int> numberList = new List<int>() { 30, 60, 90, 120, 150, 180, 270, 300, 330 };

转换成整数范围的列表,如下所示:

{ 30, 180 }
{ 270, 330 }

即:其中下一个seq大于30
另一个例子:

List<int> numberList = new List<int>() { 30, 60, 120, 150, 270, 300, 330 };

转换成整数范围的列表,如下所示:

{ 30, 60 }
{ 120, 150 }
{ 270, 330 }

我尝试过用for循环来找到最好的方法,但是我不知道从哪里开始尝试使用linq查询来做到这一点。

rslzwgfq

rslzwgfq1#

你可以写一个方法来处理分割:

IEnumerable<IList<int>> SplitValues(IList<int> input, int difference = 30)
{
    List<int> results = new List<int>();
    int last = input.First();
    foreach(var value in input)
    {
        if (value - last > difference)
        {
            yield return new[] {results.First(), results.Last()};
            results = new List<int>();
        }

        results.Add(value);
        last = value;
    }

    yield return new[] {results.First(), results.Last()};
}

这与所描述的规范匹配,返回:

{ 30, 60 }
{ 120, 150 }
{ 270, 330 }

请注意,集合中没有范围的单个值将被复制。例如,{ 30, 120, 150 }将返回:

{ 30, 30 }
{ 120, 150 }
nom7f22z

nom7f22z2#

你可以在一个linq语句中做到这一点:

var numberList = new List<int>() { 30, 60, 120, 150, 270, 300, 330 };
var section = 0;
var result = numberList
            .Select( (x, i) => new {value = x, section = (i == 0 ? 0 : ((x - numberList[i - 1]) > 30 ? ++section : section))})
            .GroupBy(x => x.section)
            .Select(x => x.Select(v => v.value).ToList()).ToList();
mqkwyuun

mqkwyuun3#

有很多种方法可以做到这一点,而且都有其优点和缺点。所以这里还有一个解决方案,希望对大家有所帮助。

public static IEnumerable<TSource[]> ToRanges<TSource>(
    this IEnumerable<TSource> source, Func<TSource, TSource, TSource, bool> isNear)
{            
    List<TSource[]> result = source./*OrderBy(value => value).*/Aggregate(
        new List<TSource[]> { new[] { source.First(), source.First() } },
        (ranges, currentValue) => {
            TSource[] currentRange = ranges.Last();
            TSource previousValue = currentRange[1];

            if (isNear(currentRange[0], previousValue, currentValue))
                currentRange[1] = currentValue;
            else
                ranges.Add(new[] { currentValue, currentValue});

            return ranges;
        }
    );

    return result;
}

示例用法:

List<int> numbers = new List<int>() { 30, 60, 90, 120, 150, 180, 270, 300, 330 };

// split by max difference
numberList.ToRanges(
    (first, previous, current) => current - previous <= 30).ToArray();
// { 30, 180 }
// { 270, 330 }

// split by max range
numberList.ToRanges(
    (first, previous, current) => current - first <= 90).ToArray();
// { 30, 120 }
// { 150, 180 }
// { 270, 330 }

此外,您不仅可以拆分整数,还可以拆分单词的第一个字母。或DateTime/TimeSpan。或者随便你怎么说。

c0vxltue

c0vxltue4#

必须使用LINQ吗?如果不是,那么:

List<int> numberList = new List<int>() { 30, 60, 120, 150, 270, 300, 330 };  

Dictionary<int, int> result = new Dictionary<int, int>();
int lastStart = numberList.First();
for(int i=1; i < numberList.Count; i++)
{
    if(numberList[i] >= lastStart + 30)
    {
        result.Add(lastStart, numberList[i]);
        if (i == numberList.Count - 1) break;
        lastStart = numberList[i + 1];
        i++;
    }
}

foreach (var item in result)
{
    Console.WriteLine("{{{0}, {1}}}", item.Key, item.Value);
}
kmb7vmvb

kmb7vmvb5#

您可以使用TakeWhile并将结果添加到另一个列表中

void SplitByRange()
{
    List<int> numberList = new List<int>() { 30, 60, 120, 150, 270, 300, 330 }; 
    IEnumerable<int> aux = new List<int>();

    int n = numberList.First();
    int skip = 0;
    List<List<int>> output = new List<List<int>>();

    while ((aux = numberList.Skip(skip).TakeWhile(o => { bool r = (o - n) <= 30; n = o; return r; })).Count() > 0)
    {
        output.Add(aux.ToList());
        skip += aux.Count();
    }
}

最后,numberList将为空,output将是列表的列表。

output[0]  // { 30, 60 }
...

当前代码将要求列表中至少有一个元素,如果您有

{ 30, 100 }

它将作为两个列表返回,每个列表中有一个元素

{ 30 }
{ 100 }
13z8s7eq

13z8s7eq6#

试试这个:

private static List<int[]> GetGroups(List<int> numberList)
{
    List<List<int>> groups = new List<List<int>>();
    numberList.Zip(numberList.Skip(1), (a, b) =>
    {
        if ((b - a) == 30)
        {
            if (groups.Count == 0)
                groups.Add(new List<int>());
            groups[groups.Count - 1].Add(a);
        }
        else if (a == b)
        {
            groups[groups.Count - 1].Add(a);
        }
        else
        {
            groups[groups.Count - 1].Add(a);
            groups.Add(new List<int>());
        }
        return a;
    }).ToList();
    groups[groups.Count - 1].Add(numberList.Last());
    return groups.Select(g => new[] { g.First(), g.Last() }).ToList();
}

样品使用:

//List<int> numberList = new List<int>() { 30, 60, 90, 120, 150, 180, 270, 300, 330 };
List<int> numberList = new List<int>() { 30, 60, 120, 150, 270, 300, 330 };
var result = GetGroups(numberList);
g0czyy6m

g0czyy6m7#

int bin = 15;
    
    var start = DateTime.Parse("08:00:00");
    var end = DateTime.Parse("09:00:00");
    
var timeFrame = Enumerable
    .Range(0, Convert.ToInt32((end.TimeOfDay.TotalMinutes - start.TimeOfDay.TotalMinutes) / bin))
    .Select((s,i) => start.AddMinutes(i * bin)).ToList();
    
    foreach (var t in timeFrame)
    {
        Console.WriteLine($"T: {t}");
    }

相关问题