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?
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);
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)
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!
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;
}
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; }
}
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)
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));
}
}