webForumDet fria alternativet

Rekursiv funktion av "djup"?

.NET

10 svar · 866 visningar · startad av Travoni

Medlem sedan okt. 20041 556 inlägg
Frågan#1

Jag skulle vilja göra en rekursiv funktion som skapar en ul-li lista utav ett innehåll i en databas.
Det finns bara ett litet krux, noderna innehåller inget "parnet-id" vilket jag tycker försvårar det hela en del. :)

Däremot så hämtas alltid raderna i "rätt ordning" och djupet på noderna (som kanske kan användas i stället).

Tänker mig nåt sånt här:

[B]Namn [red]Djup[/red][/B]
--------------------
Allt [red]0[/red]
    Bilar [red]1[/red]
        Volvo [red]2[/red]
            v70 [red]3[/red]
            xc90 [red]3[/red]
        Saab [red]2[/red]
    Båtar [red]1[/red]
        Segelbåtar [red]2[/red]
        Motorbåtar [red]2[/red]
Medlem sedan juni 20008 205 inlägg
#2

Behöver inte bli rekursivt. Pseudokod:

previousDepth = -1
för varje rad:
    for (; previousDepth > rad.djup; previousDepth--) skriv ut "</ul>"
    for (; previousDepth < rad.djup; previousDepth++) skriv ut "<ul>"
    skriv ut "<li>" + rad.namn + "</li>"
// avsluta med att stänga alla listor
for (; previousDepth > -1; previousDepth--) skriv ut "</ul>"

red. buggfix

Medlem sedan okt. 20041 556 inlägg
#3

Ok, skall jag göra tre for/while-satser för varje rad?

Typ så här?

{ 
    DataRow dr; 
    connection.Open(); 
    using (MySqlDataReader reader = command.ExecuteReader) { 
        while (reader.Read) { 
            dr = dt.NewRow(); 
            
            int previousDepth = -1; 
            while (previousDepth > rad.djup) { 
                dr("Content") = "</ul>"; 
                previousDepth -= 1; 
            } 
            while (previousDepth < rad.djup) { 
                dr("Content") += "<ul>"; 
                previousDepth += 1; 
            } 
            
            dr("Content") += "<li>" + rad.namn + "</li>"; 
            
            while (previousDepth > -1) { 
                dr("Content") += "</ul>"; 
                previousDepth -= 1; 
            } 
            dt.Rows.Add(dr); 
        } 
        reader.Close(); 
    } 
}
Medlem sedan juni 20008 205 inlägg
#4

Nej, den sista loopen, där man räknar ner previousDepth till -1, ska ligga efter att du loopat igenom svaret från databasen, så att man stänger alla ul. Typ efter anropet till reader.Close().

Medlem sedan okt. 20041 556 inlägg
#5

Oki, mycket STORT tack! :f
Funkade klockrent!

Medlem sedan aug. 20039 340 inlägg
#6

Inte för att det spelar någon roll, men funktionen är iterativ, inte rekursiv.

Medlem sedan okt. 20041 556 inlägg
#7

nitro2k01 skrev:

Inte för att det spelar någon roll, men funktionen är iterativ, inte rekursiv.

Tack för info.

Medlem sedan dec. 19996 721 inlägg
#8

Som en kul grej provade jag att göra det med webbkontroller i stället.


HtmlGenericControl baseList= new HtmlGenericControl("ol");
HtmlGenericControl currentList =baseList;
HtmlGenericControl listItem=null;
Stack<HtmlGenericControl> stack = new Stack<HtmlGenericControl>();
int currentDepth = 0;
foreach (Item item in items)
{
    if (item.Depth > currentDepth)
    {
        stack.Push(currentList);
        HtmlGenericControl newList = new HtmlGenericControl("ol");
        listItem.Controls.Add(newList);
        currentList = newList;
        
    }
    else if (item.Depth < currentDepth)
    {
        currentList=stack.Pop();
    }
    HtmlGenericControl listItem = new HtmlGenericControl("li");
    listItem.InnerText = item.Name;
    currentList.Controls.Add(listItem);
    currentDepth=item.Depth;
}
Medlem sedan juni 20008 205 inlägg
#9

Jag har insett att min algoritm är trasig, eller rättare sagt att HTML-koden den genererar är det, eftersom <ul> enbart får innehålla <li>. Alltså borde den genererade koden bli nåt i stil med

<ul>
    <li>
        Allt 
        <ul>
            <li>
                Bilar
                <ul>
                    <li>
                        Volvo 
                        <ul>
                            <li>
                                v70
                            </li>
                            <li>
                                xc90
                            </li> 
                        </ul>
                    </li>
                    <li>
                        Saab
                    </li>
                </ul>
            </li>
            <li>
                Båtar
                <ul>
                    <li>
                        Segelbåtar
                    </li>
                    <li>
                        Motorbåtar
                    </li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

Klurigt värre. Jag hinner dessvärre inte fundera på't mer idag.

Medlem sedan dec. 19996 721 inlägg
#10

Gjorde samma fel och ändrade.

Medlem sedan juni 20008 205 inlägg
#11

Nu är det förvisso på sin höjd enbart av akademiskt intresse, eftersom emissions lösning med webbkontroller är bättre, men så här kan det se ut:

def print_menu(elmts, pos, lvl):
    print "<ul>"
    while pos < len(elmts) and elmts[pos].depth == lvl:
        print "<li>"
        print elmts[pos].name
        pos += 1
        if pos < len(elmts) and elmts[pos].depth > lvl:
            pos = print_menu(elmts, pos, elmts[pos].depth)
        print "</li>"
    print "</ul>"
    return pos

# ...

elmts = [
    MenuItem("Allt", 0),
    MenuItem("Bilar", 1),
    MenuItem("Volvo", 2),
    MenuItem("v70", 3),
    MenuItem("xc90", 3),
    MenuItem("Saab", 2),
    MenuItem("Båtar", 1),
    MenuItem("Segelbåtar", 2),
    MenuItem("Motorbåtar", 2),
    MenuItem("Ideal", 3),
    MenuItem("Uttern", 3),
    MenuItem("Segway", 1)
    ]
print_menu(elmts, 0, elmts[0].depth)
256 ms totalt · 4 externa anrop · v20260731065814-full.86ec41c2
129 ms — deklarationer (db)
0 ms — hämta statistik (cache)
124 ms — hämta tråd, inlägg och bilagor (db)
121 ms — ändringar (db)