Entwickler-Ecke

Datenbanken (inkl. ADO.NET) - foreach element mit index +1 abfragen - LINQ


Glowhollow - Fr 24.05.19 14:24
Titel: foreach element mit index +1 abfragen - LINQ
Hallo Leute,

Ich hab hier ein kleines Problem. Muß ne Website parsen und auswerten, da die Website aber automatisch erstellt wird, und ich auf die Erstellung keinen Einfluss habe, und deren Datenstruktur, sehr... gewöhnungsbedürftig ist - muß ich n bischen tricksen.

Im Moment, habe ich eine eine foreach Anweisung, die sämtliche Elemente, die mir die bibliothek mshtml zurückliefert durchiteriere, aber aufgrund der fehlenden struktur der webpage muß ich einen spezialfall abfangen.

Ich werte eine Tabelle aus, und dort gibt es Felder, die leer sein können, aber nur dann, wenn das nachbarfeld kein image hat.

Ihr versteht jetzt bestimmt, das beim befüllen, der datatable, ich jetzt in der bredoiulle stecke, da ich prüfen muß, ob das nachbarfeld, ein image hat, kann das aber über die foreach noch nicht abfangen, weil die genau einen index hinterherhängt.

Ich würde das ganze gerne über Linq Lösen. Habe jedoch im moment noch keinen Ansatz, da ich mit linq noch recht neu bin.

Hier mein bisheriger Code.


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
IHTMLElement2 ie = (IHTMLElement2)oHtmlDoc.body;
IHTMLElementCollection iec = (IHTMLElementCollection)ie.getElementsByTagName("td");
IHTMLElement pastitem=null;
int indexhelper = 0;
int controlhelper = 0;
bool runonce2 = true;
foreach (IHTMLElement item in iec)
{
    if ((item.innerText == null && indexhelper == 0))
    {
        dataHolder.Rows.Add(dataHolder.NewRow());
        indexhelper++;
    }
    if (item.className == "statusEven" || item.className == "statusOdd" || item.className == "statusOK" || item.className == "status"  )
    {
        if ((item.className == "statusEven" || item.className == "statusOdd" || item.className == "status") && item.innerHTML.Contains("<IMG"))
        {
                       
        }
        else
        {
            if ((item.innerText == null && indexhelper == 0))
            {
                dataHolder.Rows.Add(dataHolder.NewRow());
                indexhelper++;
            }
            if (!(item.innerHTML.Contains("<IMG")))
            {
                if (item.innerText != null)
                {
                    dr = dataHolder.NewRow();
                    dr[0] = item.innerText;
                    dataHolder.Rows.Add(dr);
                    indexhelper++;
                }                           
            }
        }
        pastitem = item;
    }
    if (indexhelper >= 7)
    {
        indexhelper = 0;
        controlhelper++;
    }
    if (runonce2 == true && dataHolder.Rows.Count >=1)
    {
        dataHolder.Rows.RemoveAt(0);
        runonce2 = false;
    }
}


nichtwundern, controlhelper variablen etc.. sind noch zu testzwecken drin, ich wollte da mal was ausstesten.

Moderiert von user profile iconTh69: Beitragsformatierung (C#-Code) überarbeitet.

danke th69 ;) war noch am zusammenstellen.

Ich würde ja in etwa die linq abfrage so schreiben wollen, was aber nicht korrekt ist.


C#-Quelltext
1:
2:
3:
IHTMLElement query = from element in iec
                     where element.item.sourceIndex = item.sourceIndex+1
                     select element.item


Ralf Jansen - Sa 25.05.19 18:13

Da noch keiner geantwortet nehme ich mal an das, so wie eigentlich ich auch, keiner genau verstanden hat was du willst.

Ich probiere es mal allgemein.
Linq stellst du dir hier am besten als etwas vor das letztlich intern auch nichts anderes macht als du hier. Es wird über die Menge iterieren (z.b. per foreach) auf die es angewendet wird. Linq wirkt primär auf aufzählbares, in c#-sprech auf Dinge die IEnumerable implementieren und für die man einen Enumerator bekommen kann. Ein Enumerator ist etwas das eine aktuelle Position kennt und eine Methode ein nächstes Element zu bekommen. Es weiß nicht direkt etwas von Vorgängern oder Nachfolgern oder gar so etwas wie einen direkten Index um auf Elemente zuzugreifen.

Um damit ein Zugriff auf Vorgänger/Nachfolger zu bekommen musst du das gleiche tun was du in klassischen Datenbanken tun müsstest bevor es dort Window Functions gab. Ich führe diesen Vergleich mal an da du in einer Datenbank Sparte gefragt hast obwohl dein Problem nichts mit Datenbanken zu tun hat. Und in einer SQL Datenbank würdest du dazu einen Self-Join verwenden um einen Vergleich jeden Elements mit jedem anderen Element in der Liste zu bekommen und über irgendwelche Argumente Vorgänger-Nachfolger Paare an Elementen zu finden.

Genau das gleiche könntest du also hier tun und nochmal auf deine iec Liste joinen um dein Problem mit Linq zu lösen. Die Frage bliebe dann nur warum? Wenn du schon eine Lösung hast (auch wenn die nach meinen persönlichen Kriterien eher zwischen hässlich und vermutlich unnötig kompliziert schwankt) die mit einer einzelnen Schleife auskommt warum die durch ein ersetzen die eher äquivalent wäre zu 2 Schleifen? In Linq ließe sich das ganze vermutlich etwas kompakter ausdrücken. Bei der Lesbarkeit hätte ich aber schon Zweifel. Und von der Performance her bin ich mir ziemlich sicher wäre es keine Verbesserung.