-3

DateTime 項目のリストがあり、互いに 2 分以内にある項目をすべて削除したいと考えています (最初に検出された項目はそのままにしておく必要があります)。LINQを使用してこれを達成する方法を教えてもらえますか? 拡張メソッドは必要でしょうか?

明確にするために、いくつかのサンプルデータ:

00:00:00 00:01:30 00:02:30 00:05:00

返す必要があります:

00:00:00 00:05:00

4

4 に答える 4

3

したがって、ここでのアイデアは、最初に項目をグループ化することです。リスト内の項目 (並べ替え済み) を調べているときに、現在の項目が前の項目のしきい値内にある場合は同じグループに移動し、そうでない場合は独自のグループを開始する必要があります。

GroupWhile以前のアイテムと現在のアイテムが与えられた関数を受け取り、それらをグループ化する必要があるかどうかを判断する関数を作成できます。データを並べ替え、指定された条件でグループ化し、各グループの最初の項目を取得します。

public static IEnumerable<DateTime> LoneDates(
    IEnumerable<DateTime> dates, TimeSpan threshold)
{
    return dates.OrderBy(x => x)
        .GroupWhile((previous, current) => current - previous <= threshold)
        .Select(group => group.First());
}

の実装に関しては、次のように実行GroupWhileできます。

public static IEnumerable<IEnumerable<T>> GroupWhile<T>(
    this IEnumerable<T> source, Func<T, T, bool> predicate)
{
    using (var iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())
            yield break;

        List<T> list = new List<T>() { iterator.Current };

        T previous = iterator.Current;

        while (iterator.MoveNext())
        {
            if (predicate(previous, iterator.Current))
            {
                list.Add(iterator.Current);
            }
            else
            {
                yield return list;
                list = new List<T>() { iterator.Current };
            }

            previous = iterator.Current;
        }
        yield return list;
    }
}

これを読み取ると、最初のアイテムが独自のグループに配置され、次にシーケンス内の他の各アイテムが処理されます。指定された関数が現在のグループに追加する必要があることを示している場合はそうです。そうでない場合は、現在のグループが出力シーケンスに送信され、新しいグループが作成されます。

サンプル入力の使用:

var data = new List<DateTime>()
{
    DateTime.Today,
    DateTime.Today.AddMinutes(1.5),
    DateTime.Today.AddMinutes(2.5),
    DateTime.Today.AddMinutes(5),
};

var query = LoneDates(data, TimeSpan.FromMinutes(2));

Console.WriteLine(string.Join("\n", query));

結果:

2013/8/30 12:00:00 午前

2013/8/30 12:05:00 午前

これは期待される出力です。

于 2013-08-30T15:15:09.777 に答える
0

クエリ

このクエリは、2 秒未満の直前の時刻がない場合にのみ、時刻 T を取得します。

IEnumerable<DateTime> times = ...;

var query = times
    .OrderBy(x => x)
    .Throttle((x, y) => y.Subtract(x) <= TimeSpan.FromSeconds(2));

ヘルパー

public static IEnumerable<T> Throttle(
    this IEnumerable<T> source, Func<T, T, bool> collapse)
{
    var first = true;
    var prev = default(T);
    foreach (var curr in source)
    {
        if (first || !collapse(prev, curr))
        {
            yield return curr;
            first = false;
        }
        prev = curr;
    }
}
于 2013-08-30T15:17:52.460 に答える
0

非Linqの答えは、簡単なようです。

 private List<DateTime> RemoveItems(List<DateTime> times)
        {
            var newtimes = new List<DateTime>();

            var previoustime = new DateTime();

            var firsttime = times[0];

            newtimes.Add(firsttime);

            foreach (var time in times)
            {
                if (firsttime == time)
                {
                    previoustime = time;
                    continue;
                }

                if ((time - previoustime) > new TimeSpan(0,0,1,30))
                {
                    newtimes.Add(time);
                }

                previoustime = time;
            }

            return newtimes;
        }
于 2013-08-30T16:12:06.913 に答える