如何根据特定条件从列表中删除项目

时间:2017-11-05 19:11:48

标签: c# .net

我有一个对象列表,列表中的每个对象都有以下属性:

  • 文件名
  • SwVersion,
  • ControllerSN,
  • FirstDoseTime,
  • EvtTime,
  • EVT,
  • EvtOutput

首先,我需要找到所有将FirstDoseTime属性设置为特定值(1/1/1,12:00:00)的对象。让我们调用这些blankFirstDose对象。

然后,我需要搜索列表,看看对于每个blankFirstDose对象,列表中是否有另一个对象与blankFirstDose对象具有相同的属性,但FirstDoseTime属性除外(除了1/1 / 1,12:00:00)和FileName属性。

最后,我想从列表中删除任何具有不同FileName和FirstDoseTime的对应对象的blankFirstDose对象,该对象不是1/1/1,12:00:00。

这是我第一次这样做。此尝试成功运行,但是当我有大量这些对象时,需要花费太长时间。我需要更高效,更快速的东西。 谢谢你的帮助!

编辑:分析

我为一个"典型的"进行了一些系统分析。案例有助于为此讨论提供信息。在这种情况下,AllEvents列表包含40,928个LogFileEvent项,而blankFirstDoseLst包含12,092个项。

在我的系统上完成所有这些操作所需的时间大约为16秒。 几乎所有这16秒都用在两个foreach循环中。

var blankFirstDoseLst = 
    AllEvents.GroupBy(e => e.FirstDoseTime)
             .Where(g => g.FirstOrDefault().FirstDoseTime == PatientModel.DEFAULT_DATE)
             .SelectMany(g => g)
             .ToList();
List<LogFileEvent> blanksToRemove = new List<LogFileEvent>();
foreach (var evt in AllEvents)
{
    foreach (var blankEvt in blankFirstDoseLst)
    {
        if ((evt.FileName      != blankEvt.FileName) &&
            (evt.SwVersion     == blankEvt.SwVersion) &&
            (evt.ControllerSN  == blankEvt.ControllerSN) &&
            (evt.FirstDoseTime != blankEvt.FirstDoseTime) &&
            (evt.EvtTime       == blankEvt.EvtTime) &&
            (evt.Evt           == blankEvt.Evt) &&
            (evt.EvtOutput     == blankEvt.EvtOutput))
        {
            blanksToRemove.Add(blankEvt);
        }
    }
}

// Remove any duplicates ignoring first dose date and time
AllEvents.RemoveAll(e => blanksToRemove.Contains(e));

2 个答案:

答案 0 :(得分:3)

您可以使用HashSet来保留应该删除的空白。

var blanksToRemove = new HashSet<LogFileEvent>();

然后是Contains

AllEvents.RemoveAll(e => blanksToRemove.Contains(e));
当你使用List时,

将是一个O(1)操作,避免必须完成的线性搜索。如果使用列表,则包含它的时间复杂度为O(n)的顺序,其中n是列表中的项目数。

<强>更新

您可以做到的另一个变化如下。既然你想要

  

...搜索列表并查看是否为每个blankFirstDose   对象,列表中的另一个对象具有相同的精确度   属性为blankFirstDose对象,但FirstDoseTime除外   property(除了1/1 / 1,12:00之外的任何内容)和FileName   属性。

您可以删除第一个foreach语句的项目,如下所示:

foreach (var evt in AllEvents.Where(evt=>evt.FirstDoseTime != PatientModel.DEFAULT_DATE))
{
    foreach (var blankEvt in blankFirstDoseLst)
    {
        if ((evt.FileName      != blankEvt.FileName) &&
            (evt.SwVersion     == blankEvt.SwVersion) &&
            (evt.ControllerSN  == blankEvt.ControllerSN) &&
            (evt.EvtTime       == blankEvt.EvtTime) &&
            (evt.Evt           == blankEvt.Evt) &&
            (evt.EvtOutput     == blankEvt.EvtOutput))
        {
            blanksToRemove.Add(blankEvt);
        }
    }
}

这样做可以避免遍历blankFirstDoseLstAllEvents项目中FirstDoseTimeworker_processes auto; user nginx; events { worker_connections 1024; use epoll; } http { tcp_nodelay on; add_header Cache-Control no-cache; upstream servers { server 127.0.0.1:9999; server 127.0.0.1:9998; } proxy_request_buffering on; server { listen 80; client_max_body_size 200M; client_body_buffer_size 200M; server_name localhost; location / { try_files $uri @proxy_upload; } location @proxy_upload { proxy_pass_request_body on; proxy_pass http://servers; } } } 与您要查找的值不同的项目。

答案 1 :(得分:1)

感谢您收到的所有回复。我最终使用了一个自定义IEqualityComparer的hashset策略,类似于@ZdeněkJelínek所提到的。自定义IEqualityComparer实现了我之前在“if”语句中执行的检查。

这大大减少了处理时间从16秒减少到约1秒。

            // Remove any events with blank first dose time if there is a duplicate that has
            // a valid first dose time
            var blanksToRemove        = new List<LogFileEvent>();
            var blankFirstDoseEvts    = AllEvents.Where(e => e.FirstDoseTime == PatientModel.DEFAULT_DATE)
                                                 .ToList();
            var nonBlankFirstDoseEvts = new HashSet<LogFileEvent>(AllEvents.Where(e => e.FirstDoseTime != PatientModel.DEFAULT_DATE),
                                                                  new BlankFirstDoseComparer());

            foreach (var blankEvt in blankFirstDoseEvts)
            {
                if (nonBlankFirstDoseEvts.Contains(blankEvt))
                {
                    blanksToRemove.Add(blankEvt);
                }
            }

            AllEvents.RemoveAll(e => blanksToRemove.Contains(e));