web-dev-qa-db-ja.com

C#のTimeSpansの合計

TimeSpan変数を含むオブジェクトのコレクションがあります。

MyObject
{ 
    TimeSpan TheDuration { get; set; }
}

LINQを使用してそれらの時間を合計したいと思います。もちろん、(MyCollectionのrからr.TheDuration).Sum();を選択します。動かない!

TheDurationのデータ型をintに変更し、それを合計してTimeSpanに変換することを考えています。私のコレクションの各TheDurationが別の場所でタイムスパンとして使用されているため、これは厄介です。

この要約について何か提案はありますか?

46
frenchie

残念ながら、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);
99
Ani

これはうまくいきます(アニの答えに基づくコード)

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)
36
grantnz

これをクラスに入れて、拡張メソッドをタイムスパンのコレクションに追加します。

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();

出来上がり!

1
frenchie

私はこれが最もクリーンな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)
0
Matt Williams

.Aggregateではなく.Sumを使用して、次のように、作成したタイムスパン合計関数を渡すことができます。

    TimeSpan AddTimeSpans(TimeSpan a, TimeSpan b)
    {
        return a + b;
    }
0
CesarGon

これが私が試したものであり、うまくいきました:

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
Shekhar_Pro

これは、コレクションとコレクション内のプロパティの両方で機能します。

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
wonea