使用Foreach从C#中的内部循环增加外部循环

时间:2018-09-03 16:31:21

标签: c# performance linq loops nested-loops

我正在尝试搜索一组工作日,以确定该工作人员当天是否工作,并获得总计工作天数。下面的方法可以工作,但是效率很低,因为即使发现一个人一天都工作了,它仍然会在剩下的日子里继续寻找。如果我可以在满足内部条件(工作日)时以某种方式增加外部ForEach循环,那肯定会更快。 totalDaysWorked是我在下面的工作:

public class StationSupportRequest
{   
    public string   RequestNum;
    public string   Status;
    public string   Prefix;
    public string   PlantLoc;
    public DateTime Date;
    public string   Departmnt;
    public DateTime Time;
    public string   StationID;
    public string   Fixture;
    public string   Supervisor;
    public string   PartNo;
    public string   SerialNum;
    public string   FailedStep;
    public string   Reason;
    public string   OtherReason;
    public string   Details;
    public string   Urgency;
    public DateTime Date_1;
    public DateTime Time_1;
    public DateTime Date_2;
    public DateTime Time_2;
    public string   ProblemFound;
    public string   SolutionCode;
    public string   Solution;
    public double   ServiceTechHrs; 
    public double   ServiceEngHrs;
    public string   DocHistory;
    public DateTime CloseDate;
    public DateTime IniDate;
    public DateTime IniTime;
    public string   MOT;
    public string   Initiator;
    public string   Notification;
    public string   ServiceTech;
    public string   ServiceEng;
    public string   SolutionCode_1;
    public string   Solution_1;
    public string   UpdatedBy;
    public List<string> UpdatedByList;  
    public string   Revisions;
    public List<DateTime> RevisionsDateTime;
    public List<WorkedDatapoint> WorkedDataPointsList;
}
public class WorkedDatapoint
{
    public string AssignerName { get; set; }
    public string AssigneeName { get; set; }
    public DateTime Date { get; set; }
    public bool AssignedToOther { get; set; }
}

var DateRange = SSRList.Where(y => y.IniDate >= IniDate && y.CloseDate < EndDate);
//DateRange = DateRange.Where(dr => dr.Fixture != null && dr.Fixture.Length == 6); //To get valid fixtures if pivoting on "Fixture"
var groupedData = DateRange.GroupBy(x => new { DS = x.ServiceTech }).Select(x =>
{
    double totalSsrsWorkedOn = x.Select(y => y.RequestNum).Count();
    IEnumerable<TimeSpan> hoursWorked = x.Select(y => y.CloseDate - y.IniDate.AddDays(GetWeekendDaysToSubtract(y.IniDate, y.CloseDate)));
    var averageReactionTimeMinutes = x.Where(d => d.IniDate != null && d.Revisions != null)   
                      .Average(d => ((DateTime.Parse(d.Revisions.Split(',')[0]) - (DateTime)d.IniDate)).Minutes);
    double[] listOfMinutesOpenTime = x.Where(d => d.IniDate != null && d.Revisions != null)
                      .Select(d => Convert.ToDouble(((DateTime.Parse(d.Revisions.Split(',')[0]) - (DateTime)d.IniDate)).Minutes))
                      .ToArray();
    double[] listOfDaysOpenTime = x.Where(d => d.IniDate != null && d.CloseDate != null)
                .Select(d => ((DateTime)d.CloseDate - (DateTime)d.IniDate.AddDays(GetWeekendDaysToSubtract(d.IniDate, d.CloseDate))).TotalDays)
                      .ToArray();
    string testtech = x.Select(y => y.ServiceTech).FirstOrDefault();
    List<DateTime> totalDaysInDateRange = Enumerable.Range(0, 1 + EndDate.Subtract(IniDate).Days)
                                                    .Select(offset => IniDate.AddDays(offset)).ToList();
    double totalHoursLogged = x.Sum(d => d.ServiceEngHrs) + x.Sum(d => d.ServiceTechHrs);
    int assignedToOthersCount = x.SelectMany(y => y.WorkedDataPointsList)
                            .Where(z => z.AssignerName.Contains(testtech) && z.AssignedToOther == true)
                            .Count();
    int brokenWiresFixed = x.Where(d => d.SolutionCode != null)
                            .Where(d => d.SolutionCode.Contains("A01 -") || 
                            d.SolutionCode.Contains("F01 -") || 
                            d.SolutionCode.Contains("S01 -")).Count();
    int npfResults = x.Where(d => d.ProblemFound != null).Where(d => d.ProblemFound.Contains("NPF")).Count();

    int totalDaysWorked = 0;
    List<DateTime> workingDatesList = new List<DateTime>();
    totalDaysInDateRange.ForEach((day) => 
    {
        x.Select(y => y.WorkedDataPointsList).ForEach((WorkedDataPoint) =>
        {
            IEnumerable<WorkedDatapoint> dateList = WorkedDataPoint
                            .Where(y => testtech == y.AssignerName)
                            .DistinctBy(z => z.Date.Date);
                            foreach ( WorkedDatapoint date in dateList)
                            {
                                if (x.Any(b => b.Date.Date.Date == date.Date.Date.Date))
                                {
                                    workingDatesList.Add(date.Date.Date.Date);
                                    break;
                                }
                            }
        });
    });
    workingDatesList.Dump("WorkingDatesList");
    totalDaysWorked = workingDatesList.DistinctBy(b => b.Date).Count();
    /*int totalDaysWorked = 0;
    totalDaysInDateRange.ForEach((day) =>
    {
        if (AssignersList.Where(d => testtech.Contains(d.AssignerName))
                    .DistinctBy(d => d.Date.Date)
                    .Any(d => d.Date.Date == day.Date))
        { 
            totalDaysWorked++; 
        }
    }); TODO: Delete this once new is working*/
    return new
    {
        //SSRs = x,
        //Station = x.Select(d => d.StationID).FirstOrDefault(),
        //Fixture = x.Select(d => d.Fixture).FirstOrDefault(),
        //ProductTested = x.Select(d => d.Details).FirstOrDefault(),
        TestTech = testtech,
        //TestEng = x.Select(d => d.ServiceEng).Distinct().Where(d => d.Length > 0),
        TotalSSRsWorkedOn = Math.Round(totalSsrsWorkedOn, 4),
        TotalHoursLogged = Math.Round(totalHoursLogged, 4),
        AssignedToOthersCount = assignedToOthersCount,
        AssignedToOthersPercentage = 100 * Math.Round(assignedToOthersCount / (assignedToOthersCount + totalSsrsWorkedOn), 4), 
        //AverageReactionTimeMinutes = averageReactionTimeMinutes,
        AverageTimeToCompleteHours = x.Where(y => y.CloseDate != null && y.Time_1 != null && y.Time_1 != DateTime.MinValue).Select(z => (z.CloseDate - z.Time_1).TotalHours).Average(), 
        //Close = x.Where(y => y.CloseDate != null && y.Time_1 != null).Select(z => (z.CloseDate)),
        //Time = x.Where(y => y.CloseDate != null && y.Time_1 != null).Select(z => (z.Time_1)),
        MedianDaysRequestOpen = Math.Round(GetMedian(listOfDaysOpenTime), 3),
        DaysWorkedPerDateRange = totalDaysWorked,
        AveSSRsClosedPerWorkedDay = Math.Round(totalSsrsWorkedOn / totalDaysWorked, 3),
        AveHoursLoggedPerRequest = Math.Round((x.Select(y => y.ServiceTechHrs + y.ServiceEngHrs).Sum()) / totalSsrsWorkedOn, 3),
        BrokenWiresFixed = brokenWiresFixed,
        PercentageBrokenWires = 100 * Math.Round(brokenWiresFixed / totalSsrsWorkedOn, 4),
        NPFResults = npfResults, 
        PercentageNPF = 100 * Math.Round(npfResults / totalSsrsWorkedOn, 4),
    };
}).OrderByDescending(x => x.TotalSSRsWorkedOn)
.Dump("Summary");
return;

样本输出,并评估了重复的日期(workingDatesList):

  

8/1/2017 12:00:00 AM

     

8/1/2017 12:00:00 AM

     

8/1/2017 12:00:00 AM

     

2017年8月2日12:00:00 AM

1 个答案:

答案 0 :(得分:0)

对您发布的代码的几点评论:

  1. 由于您从未在最外层的循环中使用day变量,因此只需完全删除该循环即可。
  2. 为什么要测试是否在x.Any(...)上循环访问y?这似乎有根本缺陷。

我无法从您的问题陈述中识别出您的数据结构是什么,或者您实际上试图做什么。您的问题陈述当前的措辞为:

  

我正在搜索一组工作日,以确定某个工人当天是否工作,并获得总计工作天数。

似乎您正在接受名为testtechString)和totalDaysInDateRangeList<DateTime>)的输入,然后想要在某个数据结构{{1 }}(我无法推断出这是什么)x所在的位置。这种解释正确吗?

如果是这样,只需遍历String.equalsIgnoreCase(y.AssignerName, testtech) && totalDaysInDateRange.contains(y.Date)数据结构中的所有条目,然后运行上述逻辑即可。如果这不能解决您的问题,请向我们提供有关数据结构x的布局以及有关每个工作人员的信息实际上如何与该工作人员的其他数据相关联的更多信息。

开始编辑

好的,既然您已经提供了更多信息,我认为您想用以下内容替换x语句:

totalDaysInDateRange.ForEach

更改实现后,只需删除x.Select(y => y.WorkedDataPointsList).ForEach((wdp) => { if (testtech == wdp.AssignerName && IniDate.Date <= wdp.Date.Date && wdp.Date.Date <= EndDate.Date) { workingDatesList.Add(wdp.Date.Date); } }); 。我还建议将totalDaysInDateRange的类型更改为workingDatesList,因为您似乎并不关心重复的日期。如果要按时间顺序打印日期,请确保将HashSet<DateTime>转换为列表并在循环完成后对其进行排序。