简体   繁体   English

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

[英]Increment outer loop from inner loop in C# using Foreach

I am trying to search through a group of days, and determine if a worker has worked that day, and get a total of days worked. 我正在尝试搜索一组工作日,以确定该工作日是否工作,并获得总计工作日。 The below works, but is terribly inefficient since even after it finds a guy worked a day it keeps looking through the rest of those days. 下面的方法可以工作,但是效率很低,因为即使发现一个人一天都工作了,它仍然会在剩下的日子里继续寻找。 If I could somehow increment the outer ForEach loop when the inner condition (day worked) is satisfied it would surely be faster. 如果我可以在满足内部条件(工作日)时以某种方式增加外部ForEach循环,那肯定会更快。 totalDaysWorked is what I'm after below: 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;

Sample output, with the duplicate dates evaluated (workingDatesList): 样本输出,评估了重复的日期(workingDatesList):

8/1/2017 12:00:00 AM 2017年8月1日12:00:00

8/1/2017 12:00:00 AM 2017年8月1日12:00:00

8/1/2017 12:00:00 AM 2017年8月1日12:00:00

8/2/2017 12:00:00 AM 2017/8/2上午12:00:00

A couple of comments on the code you posted: 关于您发布的代码的一些注释:

  1. Since you don't ever use the day variable from the outermost loop, simply remove that loop altogether. 由于您从未在最外层的循环中使用day变量,因此只需完全删除该循环即可。
  2. Why are you testing whether x.Any(...) within a loop that iterates over y ? 为什么要测试在y上迭代的循环中是否x.Any(...) This seems fundamentally flawed. 这似乎有根本的缺陷。

I can't discern from your problem statement what your data structures are, nor what it is that you are actually trying to do. 我无法从您的问题陈述中辨别出您的数据结构是什么,或者您实际上试图做什么。 Your problem statement is currently worded as: 您的问题陈述当前的措词为:

I am trying to search through a group of days, and determine if a worker has worked that day, and get a total of days worked. 我正在尝试搜索一组工作日,以确定该工作日是否工作,并获得总计工作日。

It appears you are taking some input called testtech ( String ) and totalDaysInDateRange ( List<DateTime> ), then want to find all entries in some data structure x (I can't infer what this is) where String.equalsIgnoreCase(y.AssignerName, testtech) && totalDaysInDateRange.contains(y.Date) . 看来您正在接受一些称为testtechString )和totalDaysInDateRangeList<DateTime> )的输入,然后要查找某个数据结构x所有条目(我无法推断出这是什么),其中String.equalsIgnoreCase(y.AssignerName, testtech) && totalDaysInDateRange.contains(y.Date) Is this interpretation correct? 这种解释正确吗?

If so, simply iterate over the entries in whatever your x data structure is, and run the above logic. 如果是这样,只需遍历任何x数据结构中的条目,然后运行以上逻辑。 If this doesn't solve your problem, then please give us more information on the layout of the data structure x and how information about each worker is actually associated with the other data about that worker. 如果这不能解决您的问题,请向我们提供有关数据结构x的布局以及有关每个工作人员的信息实际上如何与该工作人员的其他数据相关联的更多信息。

BEGIN EDIT 开始编辑

OK, now that you have provided more information, I think you want to replace the totalDaysInDateRange.ForEach statement with the following: 好的,既然您已提供了更多信息,我您想用以下内容替换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);
        }
    });

After changing your implementation, simply delete totalDaysInDateRange . 更改实现后,只需删除totalDaysInDateRange I also recommend changing the type of workingDatesList to HashSet<DateTime> , since you don't seem to care about duplicate dates. 我还建议将workingDatesList的类型workingDatesListHashSet<DateTime> ,因为您似乎并不关心重复的日期。 Be sure to convert workingDatesList to a list and sort it once the loop is complete if you want the dates printed in chronological order. 如果希望按时间顺序打印日期,请确保将workingDatesList转换为列表,并在循环完成后对其进行排序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM