简体   繁体   中英

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. totalDaysWorked is what I'm after below:

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):

8/1/2017 12:00:00 AM

8/1/2017 12:00:00 AM

8/1/2017 12:00:00 AM

8/2/2017 12:00:00 AM

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.
  2. Why are you testing whether x.Any(...) within a loop that iterates over y ? 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) . Is this interpretation correct?

If so, simply iterate over the entries in whatever your x data structure is, and run the above logic. 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.

BEGIN EDIT

OK, now that you have provided more information, I think you want to replace the totalDaysInDateRange.ForEach statement with the following:

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 . I also recommend changing the type of workingDatesList to HashSet<DateTime> , since you don't seem to care about duplicate dates. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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