Увеличение внешнего цикла из внутреннего цикла в C # с использованием Foreach - PullRequest
0 голосов
/ 03 сентября 2018

Я пытаюсь выполнить поиск по группе дней и определить, работал ли работник в тот день, и получить общее количество рабочих дней. Нижеследующее работает, но ужасно неэффективно, так как даже после того, как он находит парня, работавшего день, он продолжает просматривать оставшиеся дни. Если бы я мог каким-то образом увеличить внешний цикл 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

8/2 / 2017 12:00:00 AM

1 Ответ

0 голосов
/ 03 сентября 2018

Пара комментариев к коду, который вы разместили:

  1. Поскольку вы никогда не используете переменную day из самого внешнего цикла, просто полностью удалите этот цикл.
  2. Почему вы проверяете, есть ли x.Any(...) в цикле, который повторяется по y? Это кажется в корне ошибочным.

Я не могу понять из вашей постановки проблемы, каковы ваши структуры данных или что вы на самом деле пытаетесь сделать. Ваше заявление о проблеме в настоящее время сформулировано как:

Я пытаюсь выполнить поиск по группе дней и определить, работал ли работник в тот день, и получить общее количество рабочих дней.

Похоже, вы берете какой-то ввод с именем testtech (String) и totalDaysInDateRange (List<DateTime>), а затем хотите найти все записи в некоторой структуре данных 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>, так как вам, кажется, нет дела до повторяющихся дат. Обязательно конвертируйте workingDatesList в список и сортируйте его после завершения цикла, если хотите, чтобы даты печатались в хронологическом порядке.

...