1

適切でエレガントな解決策が見つからないという問題に直面しています。ビデオに関する情報を含むクラスであるofListがあります。Videosこれらの情報には、startDateendDateおよびcameraIdプロパティがあります。

現在のデータベースには次の値があります。

         startDate      endDate

現在のデータベース

これらの値を繰り返し処理したいのですが、動画が最後の動画との差が 5 分以内で、同じcameraId場合は 1 つとしてカウントする必要があります。しかし、このタスクを達成するための適切でエレガントな方法が見つかりません。

上記の動画リストの出力は次のようになります。

  • 最初: 2013:03:01 18:25:26 -> 2013-03-01 18:34:29
  • 2 番目: 2013:03:01 18:40:26 -> 2013:03:01 18:59:29

これは私がこれまでに持っているコードです:

private void ProcessVideos(List<Video> videos)
        {
            bool isSameVideo = false;
            Video lastVideo = null;


            //debugar e ver esquema do ultimo valor do database
            DateTime startDate = DateTime.MinValue;
            DateTime endDate = DateTime.MinValue;
            for (int i = 1; i < videos.Count; i++)
            {
                TimeSpan timeSpan = new TimeSpan(videos[i].DataInicio.Ticks - videos[i - 1].DataFim.Ticks);
                if (timeSpan.Minutes > 0 && timeSpan.Minutes < 5 && videos[i].IdCamera == videos[i - 1].IdCamera)
                {
                    if (!isSameVideo)
                    {
                        isSameVideo = true;
                        startDate = videos[i - 1].DataInicio;
                        endDate = videos[i].DataFim;
                    }
                    else
                    {
                        endDate = videos[i].DataFim;
                    }
                }
                else
                {
                    if (isSameVideo)
                    {
                        i++;
                        isSameVideo = false;
                        Debug.WriteLine("inicio: {0} fim: {1}", startDate, endDate);
                        startDate = DateTime.MinValue;
                        endDate = DateTime.MinValue;
                    }
                    Debug.WriteLine("inicio: {0} fim: {1}", videos[i - 1].DataInicio, videos[i - 1].DataFim);
                }
            }
            if (startDate != DateTime.MinValue)
            {
                Debug.WriteLine("inicio: {0} fim: {1}", startDate, endDate);
            }
        }

主な質問は次のとおりです。これらの値を繰り返し処理し、タイムスパンの仕様に従って値の組み合わせを出力する適切なロジックは何ですか?

4

2 に答える 2

1

私はあなたを示すために小さな例を作成しました:

私のコンテナオブジェクト:

internal class Container
{
    public int Id { get; set; }
    public DateTime Start { get; set; }
    public DateTime Stop { get; set; }

    public override string ToString()
    {
        return "ID " + Id + ": " + Start + " -> " + Stop;
    }
}

私の方法:

    private static IEnumerable<Container> DoMerge(List<Container> elements, TimeSpan maxDiff)
    {
        var closedContainers = new List<Container>();
        var lastContainers = new Dictionary<int, Container>();

        foreach (Container container in elements.OrderBy(e => e.Start))
        {
            //First case, no previous container
            if (!lastContainers.ContainsKey(container.Id))
            {
                lastContainers[container.Id] = container;
            }
            else if (container.Start - lastContainers[container.Id].Stop > maxDiff)
                //We have a container, but not in our windows of 5 minutes
            {
                closedContainers.Add(lastContainers[container.Id]);
                lastContainers[container.Id] = container;
            }
            else
            {
                //We have to merge our two containers
                lastContainers[container.Id].Stop = container.Stop;
            }
        }

        //We have now to put all "lastContainer" in our final list
        foreach (KeyValuePair<int, Container> lastContainer in lastContainers)
        {
            closedContainers.Add(lastContainer.Value);
        }
        return closedContainers;
    }

そして、最大のタイムスパンと要素のリストを指定するだけです:

    private static void Main(string[] args)
    {
        var elements = new List<Container>
            {
                new Container {Id = 1, Start = new DateTime(2013, 3, 1, 18, 25, 26), Stop = new DateTime(2013, 3, 1, 18, 27, 29)},
                new Container {Id = 1, Start = new DateTime(2013, 3, 1, 18, 30, 26), Stop = new DateTime(2013, 3, 1, 18, 34, 29)},
                new Container {Id = 1, Start = new DateTime(2013, 3, 1, 18, 40, 26), Stop = new DateTime(2013, 3, 1, 18, 52, 29)},
                new Container {Id = 1, Start = new DateTime(2013, 3, 1, 18, 55, 26), Stop = new DateTime(2013, 3, 1, 18, 59, 29)},
            };
        foreach (Container container in DoMerge(elements, TimeSpan.FromMinutes(5)))
        {
            Console.WriteLine(container);
        }
        Console.ReadLine();
    }

これにより、2 つのオブジェクトが残っていると予想される結果が得られます。

言及されたデータの結果: ここに画像の説明を入力

于 2013-03-11T12:35:36.063 に答える
0

これが解決策です。このメソッドの要点は、ExtractVidTimes メソッドに示されています。残りはサンプルデータを作成するだけです

    [TestFixture]
public class TestyMcTest
{
    public class Vid
    {
        public int CamId;
        public DateTime Start;
        public DateTime End;
    }

    [Test]
    public void Test()
    {
        var list = new List<Vid>
            {
                //=====Combination1=======
                new Vid
                    {
                        CamId = 1,
                        Start = new DateTime(2000, 1, 1, 0, 0, 0),
                        End = new DateTime(2000, 1, 1, 0, 3, 0)
                    },
                new Vid
                    {
                        CamId = 1,
                        Start = new DateTime(2000, 1, 1, 0, 5, 0),
                        End = new DateTime(2000, 1, 1, 0, 7, 0)
                    },
                //=====Combination2=======
                new Vid
                    {
                        CamId = 1,
                        Start = new DateTime(2000, 1, 1, 0, 15, 0),
                        End = new DateTime(2000, 1, 1, 0, 18, 0)
                    },
                //=====Combination3=======
                new Vid
                    {
                        CamId = 2,
                        Start = new DateTime(2000, 1, 1, 0, 0, 0),
                        End = new DateTime(2000, 1, 1, 0, 3, 0)
                    },
                //=====Combination4=======
                new Vid
                    {
                        CamId = 2,
                        Start = new DateTime(2000, 1, 1, 0, 10, 0),
                        End = new DateTime(2000, 1, 1, 0, 13, 0)
                    }
            };

        //here is your list of vids grouped by the cam id
        var result = ExtractVidTimes(list);
    }

    //THE METHOD
    private static List<List<Vid>> ExtractVidTimes(List<Vid> list)
    {
        //Group by cam ID
        var vidGroups = list.GroupBy(vid => vid.CamId).ToList();

        //extract vids with aggregate times
        var result = vidGroups.Select(vids =>
            {
                var vidTimes = new List<Vid>();
                var finalVid = vids.OrderBy(vid=> vid.Start).Aggregate((a, b) =>
                    {
                        if (a.End.AddMinutes(5) > b.Start)
                        {
                            a.End = b.End;
                            return a;
                        }

                        vidTimes.Add(a);
                        return b;
                    });

                vidTimes.Add(finalVid);

                return vidTimes;
            }).ToList();

                    //return result.SelectMany(x=>x);  //if you want a List<vid> return ed instead of a nested list

        return result;
    }
}
于 2013-03-11T13:06:08.510 に答える