webForumDet fria alternativet

Rekursiv kolla datum metod

.NET

5 svar · 503 visningar · startad av Addeladde

Medlem sedan jan. 20013 406 inlägg
Frågan#1

Hej

Jag får inte riktigt till detta. Vet att det inte riktigt stämmer på hur jag vill ha det.

Jag vill kolla datum i en collection och se hur många tider som skulle placera bredvid varandra i en kalender. Funktionen måste göras rekursivt eftersom att de två första tiderna ligger inom samma intervall men den tredje tiden ligger bara inom samma intervall som den andra tiden. Men de måste ändå placera sig efter varandra på grund av överlappningen.

Tänk er som en kalender där tiderna ska placera sig bredvid varandra då de krockar.

Det jag vill åstadkomma är följande:

rID  start        stop     order   inIntervall
8    09.30       10.20    1        3
4    09.45       10.50    2        3
9    10.30       11.15    3        3
2    15.30       16.20    1        0

Följande har jag försökt med:


resvColl = Reservation.GetAll();
        Response.Write(resvColl.Count);
        foreach (Reservation r in resvColl)
        {
            if (r.Order == 0)
                r.InSameInterval = checkForSameInterval(r);
        }
    private int checkForSameInterval(Reservation rObj)
    {
        foreach (Reservation r in resvColl)
        {
            if (r.ReservationID != rObj.ReservationID && r.StartDateTime >= rObj.StartDateTime && r.StartDateTime.Day == rObj.StartDateTime.Day && r.StartDateTime <= rObj.StopDateTime)
            {         
                    r.InSameInterval++;
                    r.Order = r.Order + 1;
                    rObj.InSameInterval = rObj.InSameInterval + checkForSameInterval(r);
                
            }
        }
        return rObj.InSameInterval;

    }

Hela testwebbservern hänger sig när jag kör denna kod. Kan det ha med minnesläckage?

Medlem sedan maj 20012 812 inlägg
#2

Addeladde skrev:

Hela testwebbservern hänger sig när jag kör denna kod. Kan det ha med minnesläckage?

Det är inte så konstigt eftersom du inte har något slut på din rekursition.

För att rekursiva funktioner skall fungerar så måste du hela tiden jobba dig närmare och närmare slutet. I ditt fall så kontrollerar du samma collection hela tiden, och skulle du hitta ett objekt som matchar din IF sats så kommer du hoppa in i din checkFoSameInterval och köra igenom exakt samma förfarande igen och kommer hitta samma objekt som kommer gå igenom din IF sats och sedan så kommer du hoppa in i din checkForSameInterval och du kommer hitta samma objekt som går igenom din IF-sats osv osv...

Ditt problem i koden är alltså att du inte "ändrar" antalet objekt som kontrolleras, utan du har exakt samma data som kontrolleras vid varje nytt anrop till metoden, och det fungerar ju inte.

- M

Medlem sedan jan. 20013 406 inlägg
#3

Får verkligen inte till detta.
Löser jag problemet med att den bli oändlig så går den inte igenom allt. Klurigt klurigt.

Medlem sedan jan. 20013 406 inlägg
#4

Jag har fått till den men den loopar ovanligt många poster tycker jag. Någon som kan se en optimeringslösning?

private void checkForSameInterval(Reservation rObj, int order, Reservation rObjStart)
    {
        counterGlobal++;
        foreach (Reservation r in resvColl)
        {
            rObj.CheckedWith.Add(r.ReservationID);
            if (r.ReservationID != rObj.ReservationID && r.StartDateTime >= rObj.StartDateTime && r.StartDateTime <= rObj.StopDateTime)
            {
                bool check = false;
                foreach(int id in r.CheckedWith){
                    if(id==r.ReservationID)
                        check = true;
                }
                if (check == false)
                {
                    order++;
                    r.Order = order;
                    rObjStart.MatchingRID.Add(r.ReservationID);
                    checkForSameInterval(r, order, rObjStart);
                }
            }
            
            
        }
        if (rObj.ReservationID == rObjStart.ReservationID)
        {
            rObjStart.InSameInterval = rObjStart.MatchingRID.Count + 1;
            foreach (Reservation r in resvColl)
            {
                foreach (int id in rObjStart.MatchingRID)
                {
                    if (id == r.ReservationID)
                        r.InSameInterval = rObjStart.InSameInterval;
                }
            }
        }

    }
Medlem sedan juni 20008 205 inlägg
#5

En tillfixad variant av din ursprungliga kod som håller reda på vilka noder som redan besökts, och som inte besöker dem igen.

private int checkForSameInterval(Reservation rObj)
{
    Dictionary<Reservation, object> visited = new Dictionary<Reservation, object>();
    visited.Add(rObj, null);
    return checkForSameInterval(r, reservations);
}

private int checkForSameInterval(Reservation rObj, Dictionary<Reservation, object> visited)
{
    foreach (Reservation r in resvColl)
    {
        if (!visited.ContainsKey(r) && MatchesButNotEqual(r, rObj))
        {         
            visited.Add(r, null);
            r.InSameInterval++;
            r.Order = r.Order + 1;
            rObj.InSameInterval = rObj.InSameInterval + checkForSameInterval(r, visited);    
        }
    }
    return rObj.InSameInterval;
}

private static bool MatchesButNotEqual(Reservation a, Reservation b)
{
    return 
        a.ReservationID != b.ReservationID && 
        a.StartDateTime >= b.StartDateTime && 
        a.StartDateTime.Day == bStartDateTime.Day && 
        a.StartDateTime <= b.StopDateTime;
}

Använder Dictionary istället för List eftersom det ger effektivare uppslag (finns kanske nån lämpligare datasamling, men principen är densamma). Det förutsätter att GetHashCode funkar för Reservation, gör den inte det kan du använda reservations-ID som nyckel istället.

Medlem sedan jan. 20013 406 inlägg
#6

Tack!

Smart lösning så slipper man ha en variabel i själva objektet som håller reda på vilka poster som är genomloopade.

259 ms totalt · 4 externa anrop · v20260731065814-full.86ec41c2
121 ms — deklarationer (db)
0 ms — hämta statistik (cache)
132 ms — hämta tråd, inlägg och bilagor (db)
124 ms — ändringar (db)