Somme de TimeSpans en C#

j'ai une collection d'objets qui incluent un laps de Temps variable:

MyObject
{ 
    TimeSpan TheDuration { get; set; }
}

je veux utiliser LINQ pour faire la somme de ces temps. Bien sûr, (de r dans MyCollection choisir R. La durée).Sum(); ne fonctionne pas!

je pense changer le type de données de la duration en int et ensuite l'additionner et convertir la somme en une durée. Ce sera un gâchis parce que chaque durée de ma collection est utilisée comme un espace-temps ailleurs.

N'importe quelle suggestion sur ceci sommation?

38
demandé sur wonea 2011-01-16 03:33:32

7 réponses

Malheureusement, il n'y a pas une surcharge de Sum qui accepte un IEnumerable<TimeSpan>. De plus, il n'existe actuellement aucun moyen de spécifier des contraintes génériques basées sur l'opérateur pour les paramètres de type, donc même si TimeSpan est" nativement " summable, ce fait ne peut pas être facilement repris par le code générique.

une option serait, comme vous dites, de faire la somme d'un type intégral équivalent à l'espace-temps à la place, et ensuite tourner somme dans l' TimeSpan nouveau. La propriété idéale pour c'est TimeSpan.Ticks, qui font exactement l'aller-retour. Mais il n'est pas nécessaire de changer le type de propriété sur votre classe; vous pouvez juste projet:

var totalSpan = new TimeSpan(myCollection.Sum(r => r.TheDuration.Ticks));

alternativement, si vous voulez vous en tenir à la durée + opérateur pour faire la sommation, vous pouvez utiliser le Aggregate opérateur:

var totalSpan = myCollection.Aggregate
                (TimeSpan.Zero, 
                (sumSoFar, nextMyObject) => sumSoFar + nextMyObject.TheDuration);
86
répondu Ani 2011-01-16 00:51:01

Cela fonctionne bien (code sur la base de l'Ani réponse)

public static class StatisticExtensions
{    
    public static TimeSpan Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, TimeSpan> selector)
    {
        return source.Select(selector).Aggregate(TimeSpan.Zero, (t1, t2) => t1 + t2);
    }
}

Utilisation :

si Periods est une liste d'objets avec une propriété de durée

TimeSpan total = Periods.Sum(s => s.Duration)
34
répondu grantnz 2012-11-01 01:54:23

j'ai mis ceci dans une classe pour ajouter une méthode d'extension à une collection de timespans:

public static class Extensions:
{
    public static TimeSpan TotalTime(this IEnumerable<TimeSpan> TheCollection)
    {
        int i = 0;
        int TotalSeconds = 0;

        var ArrayDuration = TheCollection.ToArray();

        for (i = 0; i < ArrayDuration.Length; i++)
        {
            TotalSeconds = (int)(ArrayDuration[i].TotalSeconds) + TotalSeconds;
        }

        return TimeSpan.FromSeconds(TotalSeconds);
    }
}

donc maintenant, je peux écrire TotalDuration = (ma requête LINQ qui renvoie une collection de timespan).Tempstotal();

Voila!

1
répondu frenchie 2017-06-15 14:19:00

Vous pouvez utiliser .Aggregate plutôt que .Sum, et de passer un temps somme de fonction de ce que vous écrivez, comme ceci:

    TimeSpan AddTimeSpans(TimeSpan a, TimeSpan b)
    {
        return a + b;
    }
0
répondu CesarGon 2011-01-16 00:44:05

Voici ce que j'ai essayé et cela a fonctionné:

System.Collections.Generic.List<MyObject> collection = new List<MyObject>();
MyObject mb = new MyObject();
mb.TheDuration = new TimeSpan(100000);
collection.Add(mb);
mb.TheDuration = new TimeSpan(100000);
collection.Add(mb);
mb.TheDuration = new TimeSpan(100000);
collection.Add(mb);
var sum = (from r in collection select r.TheDuration.Ticks).Sum();
Console.WriteLine( sum.ToString());
//here we have new timespan that is sum of all time spans
TimeSpan sumedup = new TimeSpan(sum);


public class MyObject
{
    public TimeSpan TheDuration { get; set; }
}
0
répondu Shekhar_Pro 2017-06-15 14:18:08

je crois que c'est le plus propre de l'extension LINQ:

public static class LinqExtensions
{
    public static TimeSpan Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, TimeSpan> func)
    {
        return new TimeSpan(source.Sum(item => func(item).Ticks));
    }
}

Utilisation est la même:

TimeSpan total = Periods.Sum(s => s.Duration)
0
répondu Matt Williams 2017-06-15 14:25:03

cela fonctionne à la fois pour une collection, et une propriété dans une collection;

void Main()
{
    var periods = new[] {
        new TimeSpan(0, 10, 0),
        new TimeSpan(0, 10, 0),
        new TimeSpan(0, 10, 0),
    };
    TimeSpan total = periods.Sum();
    TimeSpan total2 = periods.Sum(p => p);

    Debug.WriteLine(total);
    Debug.WriteLine(total2);

    // output: 00:30:00
    // output: 00:30:00
}


public static class LinqExtensions
{
    public static TimeSpan Sum(this IEnumerable<TimeSpan> timeSpanCollection)
    {
        return timeSpanCollection.Sum(s => s);
    }

    public static TimeSpan Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, TimeSpan> func)
    {
        return new TimeSpan(source.Sum(item => func(item).Ticks));
    }
}
0
répondu wonea 2017-06-15 14:36:28