合并 类 的单个列表

Consolidate a single list of classes

我有一个 classes 列表,其中包含事件名称、时间戳和持续时间(时间跨度)。有许多重复的事件名称。我想按事件名称合并它们并添加它们的持续时间并保留最早的时间戳,除非事件具有特定名称。即,删除重复的事件名称,为相似的事件名​​称添加持续时间,并保留偶数名称中最早的时间戳。

有更好的方法吗?可能与 Linq 一起使用?

这是我试过的方法,似乎没有正确合并(仍然有重复但更少)

class:

public class eventRecords
{
    public DateTime TimeStamp { get; set; }
    public string Event { get; set; }
    public TimeSpan Duration { get; set; }
}  

我的尝试:

// allEventList is already sorted by TimeStamp, so my thinking is adding
// the first occurrence of an event to newList will keep the earliest
// TimeStamp in eventRecrods for that event
// Also - the duplicates are almost all consecutive in allEventList

var newList = new List<eventRecords>();
for (int ii = 0; ii < allEventList.Count; ii++ )
{
    newList.Add(allEventList[ii]);
    if((ii + 1) < allEventList.Count && allEventList[ii] != keyword)
    {
        if(allEventList[ii].Event == allEventList[ii+1].Event)
        {
            newList.Last().Duration = newList.Last().Duration+ allEventList[ii + 1].Duration; 
            ii = ii + 1;
        }

    }

}

例如,如果 allEventList 包含:

Event = "Action 1", TimeStamp = 08:00, Duration = TimeSpan.FromMinutes(1);
Event = "Action 1", TimeStamp = 09:00, Duration = TimeSpan.FromMinutes(1);
Event = "Action 1", TimeStamp = 10:00, Duration = TimeSpan.FromMinutes(1);
Event = "KeyWord", TimeStamp = 11:00, Duration = TimeSpan.FromMinutes(1);
Event = "Action 2", TimeStamp = 12:00, Duration = TimeSpan.FromMinutes(1);
Event = "Action 2", TimeStamp = 13:00, Duration = TimeSpan.FromMinutes(1);

newList 应包含:

Event = "Action 1", TimeStamp = 08:00, Duration = TimeSpan.FromMinutes(3);
Event = "KeyWord", TimeStamp = 11:00, Duration = TimeSpan.FromMinutes(1);
Event = "Action 2", TimeStamp = 12:00, Duration = TimeSpan.FromMinutes(2);

我想这就是你想要的:

 var list = new List<EventRecords>();

 list.Add(new EventRecords{ TimeStamp = new DateTime(2014,1,1), Event = "1", Duration = new TimeSpan(1)});
 list.Add(new EventRecords { TimeStamp = new DateTime(2013, 1, 1), Event = "1", Duration = new TimeSpan(1) }); 
 list.Add(new EventRecords { TimeStamp = new DateTime(2014, 1, 1), Event = "2", Duration = new TimeSpan(1) });
 list.Add(new EventRecords { TimeStamp = new DateTime(2012, 1, 1), Event = "3", Duration = new TimeSpan(1) });

 var output = list.GroupBy(e => e.Event)
            .Select(e => new EventRecords
            {
                Event = e.Key,
                Duration = new TimeSpan(e.Sum(ee => ee.Duration.Ticks)),
                TimeStamp = e.Select(ee => ee.TimeStamp).Min()
            });

对于具有相同事件名称的项目,将它们的时间跨度相加:

new TimeSpan(e.Sum(ee => ee.Duration.Ticks)),
//create a new timespan from the sum of all timespan ticks

并获取他们最早的时间戳:

e.Select(ee => ee.TimeStamp).Min()

只有一个条目的项目将保持不变

怎么样:

allEventList
    .GroupBy(x => x.Event)
    .Select(grouping => new eventRecords
                {
                    Event = grouping.Key,
                    TimeStamp = grouping.Min(entry => entry.TimeStamp),
                    Duration = new TimeSpan(grouping.Sum(entry => entry.Duration.Ticks))
                };

也许 grouping.Min(entry => entry.TimeStamp) 可以用 grouping.First().TimeStamp 代替。我不知道 GroupBy.

是否保留顺序

这部分相当简单

I would like to consolidate them by event name and add their durations and keep the earliest timestamp

allEventList.GroupBy(e => e.Event)
        .Select(g => new eventRecords{
             TimeStamp = g.Min(e => e.TimeStamp),
             Event = g.Key,
             Duration = new TimeSpan(g.Sum(e => e.Duration.Ticks))
         });

首先按 Event 对您的列表进行分组,这会给您一个 IEnumerable<IGrouping<string,eventRecords>>。然后使用 Select 投影这些组以构建一个新的 eventRecords,并根据要求聚合所需的属性。

实例:http://rextester.com/MTVNH46675


在回答您的评论时,您可以在使用 Where 对列表进行分组之前对其进行过滤。例如,如果您只想要事件名称长度大于 5 的事件(人为的例子!)

allEventList.Where(e => e.Event.Length>5)
            .GroupBy(e => e.Event)
            .... etc

我使用了 Northwind 数据库,但这似乎符合您的要求:

from o in Orders
where o.CustomerID != "HANAR"
group o by o.CustomerID into ox
select new 
{
    Event = ox.Key,
    Start = ox.Min (o => o.OrderDate),
    Duration = ox.Sum(o=>o.Freight)
}