Skip to main content
 首页 » 编程设计

c#之用其总和替换集合中的重复值

2024年02月04日29dflying

我有一个自定义类ModeTime的列表,它的结构如下:

private class ModeTime 
{ 
    public DateTime Date { get; set; } 
    public string LineName { get; set; } 
    public string Mode { get; set; } 
    public TimeSpan Time { get; set; } 
} 

在这个列表中我有一些项目,它们的LineName和Mode是相同的,它们被一一写在列表中。我需要对此类项目的 Time 属性求和,并在不更改 LineName 和 Mode< 的情况下将其替换为具有 Time 属性总和的项目,Date 应该取自第一个被替换的项目。下面我举个例子:

Original:                                   Modified: 
Date       | LineName | Mode   | Time               Date | LineName | Mode   | Time 
01.09.2018 | Line1    | Auto   | 00:30:00     01.09.2018 | Line1    | Auto   | 00:30:00 
01.09.2018 | Line2    | Auto   | 00:10:00     01.09.2018 | Line2    | Auto   | 00:15:00 
01.09.2018 | Line2    | Auto   | 00:05:00     01.09.2018 | Line2    | Manual | 00:02:00 
01.09.2018 | Line2    | Manual | 00:02:00     01.09.2018 | Line2    | Auto   | 00:08:00 
01.09.2018 | Line2    | Auto   | 00:08:00     01.09.2018 | Line1    | Manual | 00:25:00 
01.09.2018 | Line1    | Manual | 00:25:00     01.09.2018 | Line2    | Auto   | 00:24:00 
01.09.2018 | Line2    | Auto   | 00:05:00     02.09.2018 | Line1    | Auto   | 00:05:00 
02.09.2018 | Line2    | Auto   | 00:12:00 
02.09.2018 | Line2    | Auto   | 00:07:00 
02.09.2018 | Line1    | Auto   | 00:05:00 

我试过写方法来做,部分有效,但仍然存在一些未总结的项目。

private static List<ModeTime> MergeTime(List<ModeTime> modeTimes) 
{ 
    modeTimes = modeTimes.OrderBy(e => e.Date).ToList(); 
    var mergedModeTimes = new List<ModeTime>(); 
 
    for (var i = 0; i < modeTimes.Count; i++) 
    { 
        if (i - 1 != -1) 
        { 
            if (modeTimes[i].LineName == modeTimes[i - 1].LineName && 
                modeTimes[i].Mode == modeTimes[i - 1].Mode) 
            { 
                mergedModeTimes.Add(new ModeTime 
                { 
                    Date = modeTimes[i - 1].Date, 
                    LineName = modeTimes[i - 1].LineName, 
                    Mode = modeTimes[i - 1].Mode, 
                    Time = modeTimes[i - 1].Time + modeTimes[i].Time 
                }); 
                i += 2; 
            } 
            else 
            { 
                mergedModeTimes.Add(modeTimes[i]); 
            } 
        } 
        else 
        { 
            mergedModeTimes.Add(modeTimes[i]); 
        } 
    }  
 
    return mergedModeTimes; 
} 

我还尝试用 do {} while() 包装 for 并减少源列表 modeTimes 长度。不幸的是,它会导致循环和内存泄漏(我等到 5GB 内存使用)。

希望有人能帮助我。我搜索了这个问题,在一些熟悉的情况下人们使用 GroupBy。但我不认为它适用于我的情况,我必须对具有相同 LineName 和 Mode 的项目求和,前提是它们一一出现在列表中。

请您参考如下方法:

最原始的解决方案是这样的。

var items = GetItems(); 
var sum = TimeSpan.Zero; 
 
for (int index = items.Count - 1; index > 0; index--) 
{ 
    var item = items[index]; 
    var nextItem = items[index - 1]; 
 
    if (item.LineName == nextItem.LineName && item.Mode == nextItem.Mode) 
    { 
        sum += item.Time; 
        items.RemoveAt(index); 
    } 
    else 
    { 
        item.Time += sum; 
        sum = TimeSpan.Zero; 
    } 
} 
items.First().Time += sum; 

编辑:我错过了最后一行,您必须在其中添加剩菜。这仅适用于集合的第一个和第二个元素相同的情况。没有它,它不会将聚合时间分配给第一个元素。