Gern stehe ich zur fachlichen Unterstützung in XML-Technologien, C#.NET, VisualBasic.NET und Java zur Verfügung. Sprechen Sie mich einfach an: Mail oder ☎ 0151 . 750 360 61


CSV / C#.NET: LINQ

C#.NET: LINQ

C#.NET: LINQ

➪ LINQ (Language Integrated Query) bietet leistungsfähige Standards, diverse Datenquellen (Objektlisten, SQL-DB-Tabellen, XML-Dateien) in einer SQL-ähnlichen Syntax auszuwerten. Dabei arbeitet LINQ mit Lambda-Ausdrücken, anonymen Typen, Objektinitialisierern und Typinferenz.

Auf dieser Seite:

Nehmen Sie eine Func als Lambda-Ausdruck, die einen Integerwert als Parameter übernimmt, diesen Wert quadriert und dessen Resultat zurückliefert.


Func<int, int> fquadriere = x => x * x;

Mit dieser lokalen Func ausgerüstet,


int[] werte = new int[10];
for (int i = 1; i <= 10; i++)
{
    werte[i - 1] = fquadriere(i);
}
// Auswahl der Werte mit LINQ
var teilbardurch9 = from y 
                    in werte 
                    where y % 9 == 0 
                    select y;
// Auswertung der Auswahl mit einer foreach-Schleife
foreach (var z in teilbardurch9) 
                    Console.WriteLine(z);

pic/cs_linq_intarray.png

Alternativ können Sie eine dynamische Integer-Werteliste füllen.


// deklariere eine Liste vom Typ Integer
List<int> werte = new List<int>();
// fülle die Liste mit den quadrierten Werten von 1 bis 10
for (int i = 1; i <= 10; i++) 
                    werte.Add(
                        fquadriere(i)
                    );
// Rest wie vorher

Vorstellbar ist auch dieser bereits vorher beschriebene Ansatz:


static void Main(string[] args)
{
    Func<int, int> fquadriere = x => x * x;
    Func<int, int, List<int>> Zahlen = (start, ende) => {
        List<int> l = new List<int>();
        for (int i = start; i <= ende; i++)
            l.Add(i);
        return l;
    };
    Predicate<int> fIstGeradeZahl = x => x % 2 == 0 ? true : false;
    Action<int> ausgabe = x => Console.WriteLine($"{x,9:N2}");
    // Deklariere eine Zahlenliste von 1 bis 20
    var zahlen = Zahlen(1, 20);
    Console.WriteLine("Arbeiten mit foreach (var z in Zahlen(1,50)) ausgabe(z);");
    foreach (var z in zahlen) ausgabe(z);
    Console.WriteLine("Arbeiten mit Zahlen(1, 50).ForEach(s => ausgabe(s));");
    zahlen.ForEach(s => ausgabe(s));
    // Reihenfolge umkehren?
    // zahlen.Reverse();
    // Die Vereinigungsmenge
    var zahlen2 = Zahlen(15, 25);
    var vereinigung = zahlen.Union(zahlen2);
    Console.WriteLine("zahlen.Union(zahlen2);");
    // vereinigung ist vom Typ IEnumerable
    // daher Konvertierung in List
    vereinigung.ToList().ForEach(s => ausgabe(s));
    // Auswahl: alle durch 3 teilbaren Zahlen, absteigend sortiert
    var ergebnisliste = from y in zahlen
                        where y % 3 == 0
                        orderby y descending
                        select y;
    // Alternative:
    //var ergebnisliste = zahlen
    //                    .Where(y => y % 3 == 0)
    //                    .OrderByDescending(a => a)
    //                    .Select(b => b);
    Console.WriteLine($"Arbeiten mit ergebnisliste als System.Linq.IOrderedEnumerable, {ergebnisliste.GetType().FullName}");
    // foreach (var z in ergebnisliste) ausgabe(z);
    // Alternative: Konvertierung in eine List
    ergebnisliste.ToList().ForEach(s => ausgabe(s));
    // AuswahL: alle durch 3 teilbaren Zahlen, 
    // absteigende Sortierung fallbedingt: 
    // ist der aktuelle Wert eine gerade Zahl?
    var teilbardurch3 = zahlen
            .Where(y => y % 3 == 0)                    
            .OrderByDescending(a => fIstGeradeZahl(a)? (-a) : (a))
            .Select(b => b);
    Console.WriteLine($"Arbeiten mit teilbardurch9 als System.Linq.IOrderedEnumerable, konvertiert als List");
    teilbardurch3.ToList().ForEach(s => ausgabe(s));
    Console.ReadLine();
}        

Die beiden letzten Ergebnisse:


Arbeiten mit ergebnisliste als System.Linq.IOrderedEnumerable, System.Linq.OrderedEnumerable`2
    18,00
    15,00
    12,00
     9,00
     6,00
     3,00
Arbeiten mit teilbardurch9 als System.Linq.IOrderedEnumerable, konvertiert als List
    15,00
     9,00
     3,00
     6,00
    12,00
    18,00

// sortiert alle Zahlen von 20 bis 2 absteigend und anschließend von 1 bis 19 aufsteigend
zahlen.OrderBy(a => fIstGeradeZahl(a) ? (-a) : (a))
      .ToList()
      .ForEach(s => ausgabe(s));

PLINQ

Der Unterschied zwischen LINQ und PLINQ (parallel LINQ) ist nun, dass die LINQ-Anweisungen parallel (.AsParallel()) durchgeführt werden. Die erhoffte erhöhte Geschwindigkeit mag eintreffen; ob auch die angestrebte Sortierreihenfolge eingehalten wird, bleibt abzuwarten.


var pteilbardurch9 = Zahlen(1, 10)
                    .AsParallel()
                    .Where(y => y % 9 == 0)
                    .OrderByDescending(y => y)
                    .Select(y => y);

Das jeweilige Resultat:


    81,00
    36,00
     9,00

Möglich ist auch der Aufruf, der nur bei .AsParallel() zur Verfügung steht.


pteilbardurch9.ForAll(s => ausgabe(s));

Wenn Sie beide Aufrufe nacheinander laufen lassen, können Sie feststellen, dass die Reihenfolge´der ausgegebenen Zahlen unterschiedlich ist.


pteilbardurch9.ForAll(s => ausgabe(s));
foreach (var z in pteilbardurch9) ausgabe(z);

Auswerten von CSV mit LINQ

Mit LINQ bietet C#.NET flexible Möglichkeiten, Textdateien (zum Beispiel CSV) in XML-Dokumente zu konvertieren. Auch Gruppierungen der XML-Struktur sind leicht möglich.

Alternativ zur CSV-XML-Konvertierung via unparsed-text-lines können Sie in C#.NET/VisualBasic.NET mit LINQ arbeiten. Nehmen Sie diese CSV-Struktur:


ORTID;ORTNAME;ID;NAME;VORNAME;GEHALT;IDORT;AUSGABEN
1;Neustadt;1;Holzflos;Hugo;234.56;1;3563.1400000000003
1;Neustadt;4;Nixlos;Nicole;1234.56;1;961.6300000000001
1;Neustadt;9;Sprachlos;Stefan;5430;1;4288.02
1;Neustadt;2;Sagblos;Stefan;321.45;1;2753.9399999999996
1;Neustadt;3;Sorglos;Siggi;987.58;1;2610.96
1;Neustadt;7;Herzlos;Heini;654.21;1;415.76
2;Darmstadt;8;Rhodos;Rudi;333.33;2;740.6999999999999
2;Darmstadt;15;Kolos;Karl;456;2;181.92
2;Darmstadt;16;Sinnlos;Simone;876.54;2;155.94
2;Darmstadt;17;Hirnlos;Horst;546.77;2;38.97
2;Darmstadt;18;Wertlos;Werner;777.77;2;103.96
2;Darmstadt;19;Lustlos;Ludwig;357;2;0
3;Kapstadt;5;Wasistlos;Willi;6789;3;831.44
3;Kapstadt;10;Ruhelos;Rita;234;3;203.19
3;Kapstadt;11;Schlaflos;Susi;321;3;808.13
3;Kapstadt;12;Rielos;Lotte;456;3;1555.98
3;Kapstadt;6;Bodenlos;Betty;3450;3;324.81999999999994
3;Kapstadt;13;Muehelos;Martin;222;3;142.89000000000001
3;Kapstadt;14;Leinenlos;Liane;135;3;964.0699999999999

In C#.NET können Sie sehr einfach ein XDocument mit mehreren Teilinformationen (XDeclaration, XComment, XElement, ) generieren. Die Teilinformationen erhalten Sie unschwer über File.ReadAllLines.


var vcsv2XML = new System.Xml.Linq.XDocument(
  new System.Xml.Linq.XDeclaration("1.0", "ISO-8859-1", "yes"),
  new System.Xml.Linq.XComment("Leute Von Heute"),
  new System.Xml.Linq.XElement("ERG",
    from zeile in File.ReadAllLines(@"C:\wg\Mensch.csv")
    where (!zeile.Contains("ORTID;ORTNAME;ID;NAME;VORNAME;GEHALT;IDORT;AUSGABEN"))
    let spalte = zeile.Split(';')
    select new System.Xml.Linq.XElement("DS",
        new System.Xml.Linq.XAttribute("ortid", spalte[0]),
        new System.Xml.Linq.XElement("ortname", spalte[1]),
        new System.Xml.Linq.XElement("Menschid", spalte[2]),
        new System.Xml.Linq.XElement("NACHNAME", spalte[3]),
        new System.Xml.Linq.XElement("VORNAME", spalte[4]),
        new System.Xml.Linq.XElement("Gehalt", spalte[5]),
        new System.Xml.Linq.XElement("idort", spalte[6]),
        new System.Xml.Linq.XElement("Ausgaben", spalte[7])
      )
    )
  );
Console.WriteLine(vcsv2XML.ToString());

Das Ergebnis der Konvertierung lautet dann (verkürzte Darstellung):


<!--Leute Von Heute-->
<ERG>
  <DS ortid="1">
    <ortname>Neustadt</ortname>
    <Menschid>1</Menschid>
    <NACHNAME>Holzflos</NACHNAME>
    <VORNAME>Hugo</VORNAME>
    <Gehalt>234.56</Gehalt>
    <idort>1</idort>
    <Ausgaben>3563.1400000000003</Ausgaben>
  </DS>
  <!-- weitere Ergebnisse -->
  <DS ortid="2">
    <ortname>Darmstadt</ortname>
    <Menschid>8</Menschid>
    <NACHNAME>Rhodos</NACHNAME>
    <VORNAME>Rudi</VORNAME>
    <Gehalt>333.33</Gehalt>
    <idort>2</idort>
    <Ausgaben>740.6999999999999</Ausgaben>
  </DS>
  <!-- weitere Ergebnisse -->
  <DS ortid="3">
    <ortname>Kapstadt</ortname>
    <Menschid>5</Menschid>
    <NACHNAME>Wasistlos</NACHNAME>
    <VORNAME>Willi</VORNAME>
    <Gehalt>6789</Gehalt>
    <idort>3</idort>
    <Ausgaben>831.44</Ausgaben>
  </DS>
  <!-- weitere Ergebnisse -->
</ERG>

Gruppierungen mit LINQ

LINQ bietet auch interessante Alternativen zum Gruppieren von XML-Strukturen (vgl. , , ).

Das soeben aus CSV generierte Resultat können Sie umgehend weiter verwenden, indem Sie die mehrfach auftretenden ortname mit LINQ gruppieren, sodass jeder Ort nur einmal genannt wird.


var output = new System.Xml.Linq.XElement("Orte",
    from grort in vcsv2XML.Descendants("ortname")
    group grort by grort.Value into g
    select new System.Xml.Linq.XElement("Ort",
        g.First().Parent.Descendants("idort"),
    new System.Xml.Linq.XElement("name", g.Key)));
Console.WriteLine(output.ToString());

Das Ergebnis sieht dann so aus:


<Orte>
  <Ort>
    <idort>1</idort>
    <name>Neustadt</name>
  </Ort>
  <Ort>
    <idort>2</idort>
    <name>Darmstadt</name>
  </Ort>
  <Ort>
    <idort>3</idort>
    <name>Kapstadt</name>
  </Ort>
</Orte>

Um weitere Inhalte anzusprechen, die sich aus der Gruppierung ergeben, können Sie so vorgehen:


var output = new System.Xml.Linq.XElement("Orte",
    from grort in vcsv2XML.Descendants("ortname")
    group grort by grort.Value into g
    select new System.Xml.Linq.XElement("Ort",
    g.First().Parent.Descendants("idort"),
    new System.Xml.Linq.XElement("name", g.Key),
    from mm in g
    select (
            new System.Xml.Linq.XElement("Einwohner",
            mm.Parent.Descendants("NACHNAME"),
            mm.Parent.Descendants("VORNAME"),
            mm.Parent.Descendants("Gehalt"),
            mm.Parent.Descendants("Ausgaben")
        ))));
Console.WriteLine(output.ToString());

Das (verkürzt dargestellte) Ergebnis dieser LINQ-basierten Transformation sehen Sie hier:


<Orte>
  <Ort>
    <idort>1</idort>
    <name>Neustadt</name>
    <Einwohner>
      <NACHNAME>Holzflos</NACHNAME>
      <VORNAME>Hugo</VORNAME>
      <Gehalt>234.56</Gehalt>
      <Ausgaben>3563.1400000000003</Ausgaben>
    </Einwohner>
    <!-- weitere Ergebnisse -->
  </Ort>
  <Ort>
    <idort>2</idort>
    <name>Darmstadt</name>
    <Einwohner>
      <NACHNAME>Rhodos</NACHNAME>
      <VORNAME>Rudi</VORNAME>
      <Gehalt>333.33</Gehalt>
      <Ausgaben>740.6999999999999</Ausgaben>
    </Einwohner>
    <!-- weitere Ergebnisse -->
  </Ort>
  <Ort>
    <idort>3</idort>
    <name>Kapstadt</name>
    <Einwohner>
      <NACHNAME>Wasistlos</NACHNAME>
      <VORNAME>Willi</VORNAME>
      <Gehalt>6789</Gehalt>
      <Ausgaben>831.44</Ausgaben>
    </Einwohner>
    <!-- weitere Ergebnisse -->
  </Ort>
</Orte>

wg / 13. März 2019



Fragen? Anmerkungen? Tipps?

Bitte nehmen Sie Kontakt zu mir auf.






Vielen Dank für Ihr Interesse an meiner Arbeit.


V.i.S.d.P.: Wilfried Grupe * Klus 6 * 37643 Negenborn

☎ 0151. 750 360 61 * eMail: info10@wilfried-grupe.de

www.wilfried-grupe.de/cs_LINQdemo2.html