Laden...

Gruppieren der Spalten in einer List<List<string>> Struktur

Erstellt von Sythus vor 8 Jahren Letzter Beitrag vor 8 Jahren 3.732 Views
S
Sythus Themenstarter:in
166 Beiträge seit 2009
vor 8 Jahren
Gruppieren der Spalten in einer List<List<string>> Struktur

Hallo zusammen,

ich hänge gerade bei einem Problem etwas in der Luft und hoffe ihr könnt mir helfen.


// Eine Liste mit vielen Zeilen die wiederum pro Zeile mehrere Spalten enthält
List<List<string>> lines = new List<List<string>>();

// In der Liste steht z.B.
// 1. Zeile: A, B, C
// 2. Zeile: A, B, D
// 3. Zeile: A, C, E
// Wieviel Spalten eine Zeile hat ist unbekannt.
// Ich möchte nun gruppieren das am ende die folgende Struktur heraus kommt:

// 
// A, B, C
//   ,   , D
// A, C, E

// Also quasi eine Gruppierung nach einer unbekannten Anzahl an spalten, damit Werte nicht doppelt übereinander stehen.


Hat jemand eine Idee?

Noch ein Beispiel:


Welt, Europa, Deutschland
Welt, Europa, England,
Welt, Europa, Frankreich

wird in der Ausgabe zu

Welt, Europa, Deutschland
                    England
                    Frankreich

Vielleicht bietet sich auch eine andere Struktur an.

Danke und viele Grüße,
Sythus

W
955 Beiträge seit 2010
vor 8 Jahren

Hi,

schau doch einfach nach ob ein Vorgänger existiert und dieser denselben Wert hat.

3.003 Beiträge seit 2006
vor 8 Jahren

Möchtest du die äußere Liste sortieren (quasi alphabetisch bzw. wie ein Inhaltsverzeichnis) und dann so ausgeben, dass jeweils nur die sich unterscheidenden Elemente mit entsprechender Einrückung dargestellt werden ?


a b c d                        (abcd)
           e f                      (abcdef)
      g h i                      (abghi)
         j k                     (abgjk)

Dafür müsste jedes Zeilen-Element über seine Vorgänger Bescheid wissen. Also vor der Ausgabe prüfen, wieviele Elemente zu Beginn übereinstimmen.

Ob eine einfache List<string> da das Mittel der Wahl ist, würde ich mir noch einmal überlegen.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

5.657 Beiträge seit 2006
vor 8 Jahren

Ob eine einfache List<string> da das Mittel der Wahl ist, würde ich mir noch einmal überlegen.

Nach den Anforderungen zu urteilen, wird hier wohl eher eine hierarchische Datenstruktur benötigt:


public class Node
{
  public string Name { get; set; }
  public Node ParentNode { get; set; }
  public List<Node> ChildNodes { get; set; }
}

Christian

Weeks of programming can save you hours of planning

3.003 Beiträge seit 2006
vor 8 Jahren

Decorator reicht.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

S
Sythus Themenstarter:in
166 Beiträge seit 2009
vor 8 Jahren

Hallo und vielen Dank für Eure Rückmeldungen.

Das mit der Node Struktur gefällt mir gut.. aber ich habe ehrlich gesagt das Problem diese ordentlich zu füllen

Die Daten kommen Beispielsweise so:

Welt, Europa, Deutschland
Welt, Europa, England
Welt, Europa, Frankreich

Ich bräuchte folgende Struktur.


Node.Name = Welt
{
  Node.Name = Europa
  {
     Node.Name = Deutschland
     Node.Name = England
     Node.Name = Frankreich
  }
}

Kann mich da jemand in die richtige Richtung schieben?

Danke 😃

Die Struktur sollte beliebig tief sein können.

5.657 Beiträge seit 2006
vor 8 Jahren

Dann bräuchtest du eine Zuordnung, um einen bereits existierenden Knoten anhand dessen Namen wiederzufinden, z.B. mit einem Dictionary<string, Node>.

Mit der TryGetValue(string, out Node)-Methode kannst du bereits bestehende Knoten finden bzw. herausfinden, ob es noch keinen Knoten gibt. Wenn es auf mehreren Ebenen Knoten mit dem gleichen Namen gibt (z.B. Welt - Australien - Australien), dann mußt du die Knoten für alle drei Ebenen getrennt verwalten.

Christian

// Edit:

Noch eleganter fände ich allerdings eine Umsetzung mit Linq. Man könnte z.B. die GroupBy-Methode verwenden, um die Hierarchie abzubilden. Das sieht dann etwa so aus:


// Testdaten
var countries = new List<string>() 
{
	"Welt,Europa,Deutschland",
	"Welt,Europa,England",
	"Welt,Europa,Frankreich",
	"Welt,Australien,Australien"	
};

// Konvertierung
Node worldNode = countries
	.Select(m => m.Split(','))
	.GroupBy(m => new { Continent = m[1], Planet = m[0] } ) // Nach Erdteil gruppieren
	.GroupBy(m => m.Key.Planet) // Nach "Planet" gruppieren => "Welt"-Knoten
	.Select(m => new Node() // In Hierarchie konvertieren
		{
			Name = m.Key, // "Planet"
			ChildNodes = m.Select(n => new Node()
				{
					Name = n.Key.Continent, // Erdteil
					ChildNodes = n.Select(o => new Node()
						{
							Name = o[2],  // Land
							ChildNodes = null
						}).ToList()
				}).ToList()
		})
	.Single(); // "Welt"-Knoten auswählen

In dem Beispiel verzichte ich auf die Node.Parent-Eigenschaft. Wenn diese im Programm benötigt wird, muß man sie noch irgendwie (möglichst elegant) setzen.

Weeks of programming can save you hours of planning

S
Sythus Themenstarter:in
166 Beiträge seit 2009
vor 8 Jahren

Hi Christian,

danke für deine Antwort.
das funktioniert gut, so lange man die Menge der Einträge kennt. Die Struktur innerhalb ist aber unbekannt, auch die Tiefe.

Ich versuche es aber mal in die Richtung weiter 😃

DAnke und VG

3.003 Beiträge seit 2006
vor 8 Jahren

Wie gesagt, Decorator. Grob gesagt eine Objekthierarchie, die Verweise auf vorangehende Objekte derselben Klasse enthalten. Damit sollte das ganze sehr schmerzfrei in beliebiger Tiefe gehen. Google mal danach und schau dir ein paar Beispiele an.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

I
15 Beiträge seit 2015
vor 8 Jahren

Das sieht nach einem Gruppenwechsel aus, vielleicht hilft dir das weiter Gruppenwechsel

I
15 Beiträge seit 2015
vor 8 Jahren

Das sollte für beliebige zweidimensionale Arrays funktionieren:

void test()
{
    controlBreak(
        new string[,]
    {
        {"A", "B", "C"},
        {"A", "C", "D"},
        {"B", "B", "D"},
        {"B", "A", "B"},
        {"B", "A", "C"},
        {"B", "A", "D"}
    });

    controlBreak(
        new string[,]                
    {
        {"A", "B", "C", "1"},
        {"A", "B", "D", "2"},
        {"A", "B", "D", "3"},
        {"A", "C", "F", "1"},
        {"B", "C", "F", "1"},
        {"B", "C", "D", "1"}
    });
}
static void controlBreak(string[,] array)
{
    for (int rowIndex = 0; rowIndex < array.GetLength(0); rowIndex++)
    {
        bool b = true;
        for (int colIndex = 0; colIndex < array.GetLength(1); colIndex++)
        {
            if (rowIndex == 0 || !b || array[rowIndex - 1, colIndex] != array[rowIndex, colIndex])
            {
                Debug.Print(new string('-', colIndex) + array[rowIndex, colIndex]);
                if (rowIndex != 0)
                    b = false;
            }
        }
    }
}
5.657 Beiträge seit 2006
vor 8 Jahren

Das sollte für beliebige zweidimensionale Arrays funktionieren

Aber nur, wenn sie schon in der richtigen Reihenfolge sortiert sind.

Christian

Weeks of programming can save you hours of planning