TimeSpan変数を含むオブジェクトのコレクションがあります。
MyObject
{
TimeSpan TheDuration { get; set; }
}
LINQを使用してそれらの時間を合計したいと思います。もちろん、(MyCollectionのrからr.TheDuration).Sum();を選択します。動かない!
TheDurationのデータ型をintに変更し、それを合計してTimeSpanに変換することを考えています。私のコレクションの各TheDurationが別の場所でタイムスパンとして使用されているため、これは厄介です。
この要約について何か提案はありますか?
残念ながら、IEnumerable<TimeSpan>
を受け入れるSum
のオーバーロードはありません。さらに、型パラメーターに演算子ベースの一般的な制約を指定する現在の方法はないため、TimeSpan
は「自然に」加算可能ですが、その事実を一般的なコードで簡単に取得することはできません。
1つのオプションは、あなたが言うように、代わりにタイムスパンに相当する整数型を合計し、that合計をTimeSpan
に再度変換することです。このための理想的なプロパティは TimeSpan.Ticks
であり、正確に往復します。ただし、クラスのプロパティタイプを変更する必要はまったくありません。あなたは単にプロジェクトすることができます:
var totalSpan = new TimeSpan(myCollection.Sum(r => r.TheDuration.Ticks));
または、TimeSpanの+
演算子を使用して合計を行う場合は、Aggregate
演算子を使用できます。
var totalSpan = myCollection.Aggregate
(TimeSpan.Zero,
(sumSoFar, nextMyObject) => sumSoFar + nextMyObject.TheDuration);
これはうまくいきます(アニの答えに基づくコード)
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);
}
}
使用法 :
PeriodsがDurationプロパティを持つオブジェクトのリストである場合
TimeSpan total = Periods.Sum(s => s.Duration)
これをクラスに入れて、拡張メソッドをタイムスパンのコレクションに追加します。
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);
}
}
これで、TotalDuration =(timespanのコレクションを返すLINQクエリ)を記述できます。TotalTime();
出来上がり!
私はこれが最もクリーンな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));
}
}
使い方は同じです:
TimeSpan total = Periods.Sum(s => s.Duration)
.Aggregate
ではなく.Sum
を使用して、次のように、作成したタイムスパン合計関数を渡すことができます。
TimeSpan AddTimeSpans(TimeSpan a, TimeSpan b)
{
return a + b;
}
これが私が試したものであり、うまくいきました:
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; }
}
これは、コレクションとコレクション内のプロパティの両方で機能します。
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));
}
}