myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Entwicklung » Grundlagen von C# » CSV-Zeilen mit gleichem Datum zusammenfassen
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

CSV-Zeilen mit gleichem Datum zusammenfassen

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
Demokrit
myCSharp.de-Mitglied

Dabei seit: 20.11.2018
Beiträge: 10


Demokrit ist offline

CSV-Zeilen mit gleichem Datum zusammenfassen

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo,

Ich suche seit einem Tag nach einer Lösung und finde tausende Sachen zu dem Thema allgemein, aber nichts was ich persöhnlich auf mein Problem anwenden und verstehen kann.


Ich lese von einer CSV Datei Daten ein. Die Daten werden in einem 2 Dimensionalen Array gespeichert. So weit verstehe ich alles.

XML-Code:
16.11.2018 14:17:15;0;5;0;0;0
16.11.2018 14:21:54;2;1;3;1;2
16.11.2018 14:24:38;1;1;0;1;0
16.11.2018 14:25:19;0;5;1;4;2

Die einzelnen Daten werden durch ein ; getrennt.


Problem/Aufgabe:

Ich will das Zeilen, die das gleiche Datum haben, addiert werden also das wenn es zum Beispiel die 2 Zeilen geben würde

XML-Code:
16.11.2018 12:18:46;1;1;1;1;1
16.11.2018 12:18:47;1;1;1;1;1

Sollen die Mit dem gleichen datum addiert werden also das es im Prinzip eine Zeile gibt die so aussieht.

XML-Code:
16.11.2018 12:18:46;2;2;2;2;2

Meine Idee wäre jetzt jede Zeile einzeln in ein 1-Dimensionales array abzuspeichern und dann dann in ein Dictionary umzuwandeln mit <Date.Time, int[]>.
Ich hab nur leider absolut keine Ahnung wie ich das machen sollte und finde bzw verstehe es auch nicht wirklich wenn ich bei google nachschaue.


Der Ganze Code:

C#-Code:
namespace ConsoleApp48
{
    class Program
    {
        static void Main(string[] args)
        {
            string filePath = @"C: \Users\-------------\Csvsave\SaveDatei.csv";
            System.IO.StreamReader sr = new System.IO.StreamReader(filePath);
            var lines = new List<string[]>();
            while (!sr.EndOfStream)
            {
                string[] Line = sr.ReadLine().Split(';');
                lines.Add(Line);
            }

            string[][] DatenSatzAuslesen = lines.ToArray();

            for (int i = 0; i < DatenSatzAuslesen.Length; i++) //i = zeilenindex
            {
                for (int j = 1; j < DatenSatzAuslesen[i].Length; j++) //j = spaltenindex
                {
                    Console.Write("{0} \n",DatenSatzAuslesen[i][j]);
                }
            }
            Console.ReadLine();
        }
    }
}
20.11.2018 10:30 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
gfoidl gfoidl ist männlich
myCSharp.de-Team

avatar-2894.jpg


Dabei seit: 07.06.2009
Beiträge: 6.600
Entwicklungsumgebung: VS 2019
Herkunft: Waidring


gfoidl ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo Demokrit,

nimm / erstell dir eine ordentliche Datenstruktur, zerlege es in einfache Methoden und dann geht es fast von alleine.

Schau mal (die Bezeichner hab ich mangels Kontext nicht besser wählen können, sollten aber schon sinnvoller sein):

C#-Code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            var parser = new Parser();

            Dictionary<DateTime, Value> result = parser.GetMergedItems("data.csv");
        }
    }

    public class Parser
    {
        public Dictionary<DateTime, Value> GetMergedItems(string fileName, bool hasHeader = false)
        {
            var mergedItems = new Dictionary<DateTime, Value>();
            IEnumerable<(DateTime, Value)> items = ParseLines(fileName, hasHeader);

            foreach ((DateTime Date, Value Value) item in items)
            {
                if (mergedItems.ContainsKey(item.Date))
                    mergedItems[item.Date] += item.Value;
                else
                    mergedItems.Add(item.Date, item.Value);
            }

            return mergedItems;
        }

        private static IEnumerable<(DateTime Date, Value Value)> ParseLines(string fileName, bool hasHeader)
        {
            using (StreamReader sr = File.OpenText(fileName))
            {
                if (hasHeader) sr.ReadLine();

                while (!sr.EndOfStream)
                {
                    string line   = sr.ReadLine();
                    string[] cols = line.Split(';');

                    yield return ParseValue(cols);
                }
            }
        }

        private static (DateTime, Value) ParseValue(string[] cols)
        {
            if (!DateTime.TryParse(cols[0], out DateTime dt))
                throw new Exception(".....");

            Action<string, Action<int>> action = (s, setter) =>
            {
                if (!int.TryParse(s, out int tmp))
                    throw new Exception("...");

                setter(tmp);
            };

            Value value = default;
            action(cols[1], i => value.A = i);
            action(cols[2], i => value.B = i);
            action(cols[3], i => value.C = i);
            action(cols[4], i => value.D = i);
            action(cols[5], i => value.E = i);

            return (dt, value);
        }
    }

    [DebuggerDisplay("{A} | {B} | {C} | {D} | {E}")]
    public struct Value
    {
        public int A { get; set; }
        public int B { get; set; }
        public int C { get; set; }
        public int D { get; set; }
        public int E { get; set; }

        public static Value operator +(Value a, Value b)
        {
            return new Value
            {
                A = a.A + b.A,
                B = a.B + b.B,
                C = a.C + b.C,
                D = a.D + b.D,
                E = a.E + b.E
            };
        }
    }
}

Anmerkung: hier geht es explizit um das Addieren von Zeilen / Einträgen mit dem gleichen Datum, daher wurde das Addieren auch direkt einkodiert. Um das generischer zu erledigen, wäre ein "Aggregator" passender und wie hier im konkreten Fall dann ein "SumAggregator" o.ä.
Auf diese Weise kann die Addition einfach gegen z.B. Mittelwert ausgetauscht werden, ohne dass der eigentliche Code verändert werden muss. Das würde dann so ausschauen:

C#-Code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            var parser     = new Parser();
            var aggregator = new SumAggregator();

            Dictionary<DateTime, Value> result = parser.GetMergedItems("data.csv", aggregator);
        }
    }

    public class Parser
    {
        public Dictionary<DateTime, Value> GetMergedItems(string fileName, IAggregator aggregator, bool hasHeader = false)
        {
            var mergedItems = new Dictionary<DateTime, Value>();
            IEnumerable<(DateTime, Value)> items = ParseLines(fileName, hasHeader);

            foreach ((DateTime Date, Value Value) item in items)
            {
                if (mergedItems.TryGetValue(item.Date, out Value value))
                    mergedItems[item.Date] = aggregator.Operate(item.Value, value);
                else
                    mergedItems.Add(item.Date, item.Value);
            }

            return mergedItems;
        }

        private static IEnumerable<(DateTime Date, Value Value)> ParseLines(string fileName, bool hasHeader)
        {
            using (StreamReader sr = File.OpenText(fileName))
            {
                if (hasHeader) sr.ReadLine();

                while (!sr.EndOfStream)
                {
                    string line = sr.ReadLine();
                    string[] cols = line.Split(';');

                    yield return ParseValue(cols);
                }
            }
        }

        private static (DateTime, Value) ParseValue(string[] cols)
        {
            if (!DateTime.TryParse(cols[0], out DateTime dt))
                throw new Exception(".....");

            Action<string, Action<int>> action = (s, setter) =>
            {
                if (!int.TryParse(s, out int tmp))
                    throw new Exception("...");

                setter(tmp);
            };

            Value value = default;
            action(cols[1], i => value.A = i);
            action(cols[2], i => value.B = i);
            action(cols[3], i => value.C = i);
            action(cols[4], i => value.D = i);
            action(cols[5], i => value.E = i);

            return (dt, value);
        }
    }

    public interface IAggregator
    {
        Value Operate(Value a, Value b);
    }

    public class SumAggregator : IAggregator
    {
        public Value Operate(Value a, Value b) => new Value
        {
            A = a.A + b.A,
            B = a.B + b.B,
            C = a.C + b.C,
            D = a.D + b.D,
            E = a.E + b.E
        };
    }

    [DebuggerDisplay("{A} | {B} | {C} | {D} | {E}")]
    public struct Value
    {
        public int A { get; set; }
        public int B { get; set; }
        public int C { get; set; }
        public int D { get; set; }
        public int E { get; set; }
    }
}

Und dann wäre es noch schön wenn das weitergetriebe wird und Unit-Tests erstellt werden, so dass das korrekte Funktionieren der Klassen / Methoden geprüft werden kann.

mfG Gü
20.11.2018 12:00 Beiträge des Benutzers | zu Buddylist hinzufügen
Florian Reischl Florian Reischl ist männlich
myCSharp.de-Poweruser/ Experte

avatar-2880.jpg


Dabei seit: 16.10.2007
Beiträge: 1.564
Entwicklungsumgebung: Visual Studio * | SQL Server *
Herkunft: München


Florian Reischl ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo

Ist Geschmackssache mit deinem verschachteltem string-Array, aber du kannst z.B. über Linq recht einfach gruppieren und dann Aggretsfunktionen anwenden.

C#-Code:
        [TestMethod]
        public void MyTestMethod()
        {
            var arr = new string[][]
            {
                new string[] { "16.11.2018 12:18:46", "1", "1", "1", "1", "1" },
                new string[] { "16.11.2018 12:18:46", "1", "1", "1", "1", "1" },
                new string[] { "17.11.2018 12:18:46", "1", "1", "1", "1", "1" }
            };

            var result = arr.GroupBy(row => row[0])
                            .Select(g => new
                            {
                                Key = g.Key,
                                C1 = g.Sum(row => int.Parse(row[1])),
                                C2 = g.Sum(row => int.Parse(row[2])),
                                C3 = g.Sum(row => int.Parse(row[3])),
                                C4 = g.Sum(row => int.Parse(row[4])),
                                C5 = g.Sum(row => int.Parse(row[5])),
                            }).ToArray();

        }

Viele Grüße
Flo
20.11.2018 12:03 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 11 Monate.
Der letzte Beitrag ist älter als 11 Monate.
Antwort erstellen


© Copyright 2003-2019 myCSharp.de-Team | Impressum | Datenschutz | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 14.11.2019 22:53