Wie man in einer Matrix nach Kennwert sortiert

2021-06-30

Die Sortierung von Daten ist ein sehr wichtiges Analysewerkzeug, mit dem Sie die Dynamik von Wachstum oder Rückgang schnell beurteilen können, sowie eine einfache Rangfolge der Daten für eine einfache Wahrnehmung. Das Matrix-Objekt in der aktuellen Version von FastReport .NET ermöglicht es Ihnen, nur die Dimensionen zu sortieren. Sie erstellen zum Beispiel einen Bericht, der die Verkaufsstatistiken der Mitarbeiter nach Jahr anzeigt. Die Matrix hat eine Gruppierung der Daten nach Jahren und Monaten. Und wir müssen innerhalb jeder Gruppe sortieren - Jahr. Mit den internen Sortierwerkzeugen können Sie die Namen der Mitarbeiter, Jahre und Monate sortieren, aber nicht die Daten selbst. Insbesondere, wenn Sie nach einer bestimmten Spalte sortieren möchten.

Auswählen der Sortierreihenfolge für die Messung Name

Um nach einer bestimmten Spalte der erstellten Matrix zu sortieren (z. B. nach einem bestimmten Mitarbeiter), müssen Sie das Berichtsskript verwenden. Es gibt zwei Möglichkeiten, die erstellte Matrix zu sortieren - Zeilen oder Zellen verschieben.

Auf den ersten Blick scheint es, dass das Verschieben der Zeilen eine bessere Lösung wäre, da beim Sortieren die Ausgabereihenfolge der gesamten Zeile und nicht einer bestimmten Zelle geändert wird. Und dies wird in der Tat die richtigste Lösung sein, aber nicht immer.

Wir werden den Fall berücksichtigen, dass das Verschieben von Zeilen nicht funktioniert. Wenn Ihre Matrix Gruppen mit Untergruppen in Dimensionen hat, gibt es Probleme beim Verschieben der Zeile, die in der Gruppe an erster Stelle steht. Eine solche Zeile hat den Gruppennamen in der ersten Zelle. Nachfolgende Zeilen aus der Gruppe haben einen leeren Wert in der ersten Zelle. Da sich die Ausgabereihenfolge der ersten Zeile in der Gruppe während des Sortiervorgangs verändern kann, tritt ein Fehler auf, wenn eine Zeile mit einem leeren Gruppentitel an ihre Stelle tritt.

Um solche Probleme zu vermeiden, müssen Sie die Zellen in der notwendigen Spalte sortieren. Das heißt, Sie sortieren zuerst die gewünschte Spalte, und dann sortieren Sie mit Hilfe eines Satzes von Zellindizes alle anderen Spalten in der Matrix nach ihr. Diese Methode ist natürlich viel zeitaufwändiger.

Schauen wir uns beide Fälle anhand eines Beispiels an. Also, der erste Fall ist das Sortieren von Matrixzeilen durch Löschen und Einfügen von Zeilen in der resultierenden Matrix.

Schauen wir uns die Ausgangsmatrix an, die wir sortieren müssen:

Die ursprüngliche Matrix

Dieser Screenshot zeigt eine einfache Matrix, die keine Gruppen mit Untergruppen hat. Für diesen Fall ist es ideal, die Zeilen zu verschieben. Tatsächlich werden wir zuerst die notwendigen Zeilen löschen und sie dann in der gewünschten Reihenfolge einfügen. All dies wird mit Hilfe des Report-Skripts realisiert.

Nehmen wir an, wir müssen die Matrix nach der Spalte für 2011 sortieren. Wir müssen die laufende Nummer dieser Spalte ermitteln und die Daten für alle ihre Zellen abrufen, mit Ausnahme der resultierenden Summe Total.

Fügen wir das Ereignis ModifyResult für das Matrix-Objekt hinzu:

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
51
52
53
public class ReportScript
 {
 // Paarschlüssel ist ein Wert in der Matrixzelle, Paarwert ist y-Koordinate der Zelle
 // auf diese Weise wird das Wörterbuch nach Zellwert sortiert
 private SortedDictionary<double, int> numbers = new SortedDictionary<double, int>();
 
 private void Matrix1_ModifyResult(object sender, EventArgs e)
 {
 int x = 1;
 int y = 2;
 
 // wir sammeln Zellwerte in der Spalte für 2011, wir werden danach sortieren
 for ( ; y < Matrix1.ResultTable.RowCount - 1; y++)
 {
 object val = Matrix1.ResultTable.GetCellData(x, y).Value;
 double dval = 0.0;
 if (val != null)
 { 
 // hier ist es wichtig, die Wertetypen zu kennen bzw. zu überprüfen
 // in diesem Beispiel ist das Format der Zelle Currency, also wandeln wir es zunächst in eine Zeile um
 // Zellenformat ist standardmäßig string
 Double.TryParse(val.ToString(), out dval);
 numbers.Add(dval, y);
 }
 // Fügen wir dem Wörterbuch ein Paar mit dem Wert 0.0 hinzu, falls die Zelle eine leere Zeile enthält
 // als Ergebnis werden leere Zeilen bei der Sortierung berücksichtigt und gehen als erste durch
 else
 {
 numbers.Add(dval, y);
 }
 }
 
 // Kopieren der Matrixzeilen in ein Hilfsarray
 // nehmen wir dann die erforderlichen Zeilen daraus und fügen wir sie in die Matrix ein object[] originalRows = Matrix1.ResultTable.Rows.ToArray();
 
 int i = 2; // Nummer der Zeile, ab der wir mit dem Löschen von Zeilen in der Matrix beginnen
 // löschen wir nun die zweite Zeile in der Matrix so oft, wie wir aussortieren müssen
 // die ganze Zeit entfernen wir die zweite Zeile, weil nach ihrer Entfernung alle Zeilen um eine Position nach oben rücken
 for (int j = 0; j < numbers.Count; j++)
 {
 Matrix1.ResultTable.Rows.RemoveAt(i);
 }
 
 i = 2; 
 // jetzt einfach alle Zeilen in der Reihenfolge der sortierten Liste hinzufügen
 foreach (int v in numbers.Values)
 {
 int rowNum = v;
 Matrix1.ResultTable.Rows.Insert(i, originalRows[rowNum] as TableRow);
 i++;
 }
 }
 }

 

Tatsächlich besteht der Kern der Methode darin, Zellwerte und ihre Indizes aus der gewünschten Spalte zu lesen und in das sortierte Wörterbuch zu schreiben. Da wir die Indizes der Zellen und folglich der Zeilen haben, können wir die Zeilen in der richtigen Reihenfolge aneinanderreihen. Dazu kopieren wir die Zeilen aber zunächst in eine temporäre Liste. Löschen wir dann alle Zeilen und fügen wir sie entsprechend den Indizes im sortierten Zellwörterbuch ein. Zum Einfügen verwenden wir die in der temporären Liste gespeicherten Matrixzeilen.

 

Als Ergebnis erhalten wir eine Matrix, sortiert nach der Spalte mit dem Jahr 2011:

Matrix sortiert nach Spalte Jahr 2011

Dies ist das einfachste Beispiel für eine Matrixsortierung. Stellen wir uns nun vor, dass wir auf der linken Seite Gruppen für Messungen haben und wir innerhalb jeder Gruppe sortieren. Wie bereits erwähnt, ist in diesem Fall die Sortierung von Zeilen nicht geeignet. Betrachten wir die Zellsortierung.

Lassen wir uns die Matrix aus dem vorherigen Beispiel umdrehen:

Invertierte Matrix

Erstellen Sie außerdem einen ModifyResult-Ereignishandler für die Matrix:

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
public class ReportScript
 {
 
 public class DescendingComparer<T>: IComparer<T> where T : IComparable<T>
 {
 public int Compare(T x, T y)
 {
 return y.CompareTo(x); 
 }
 }
 
 // Paarschlüssel ist ein Wert in der Matrixzelle, Paarwert ist y-Koordinate der Zelle
 // auf diese Weise wird das Wörterbuch nach Zellwert sortiert
 private SortedList<int, double> numbers = new SortedList<int, double>();
 
 private void Matrix1_ModifyResult(object sender, EventArgs e)
 {
 int x = 3;
 int y = 2;
 
 Dictionary<int, double> cellsMonth = new Dictionary<int, double>();
 Dictionary<int, double> cellsFirst = new Dictionary<int, double>();
 Dictionary<int, double> cellsSecond = new Dictionary<int, double>();
 Dictionary<int, double> cellsThird = new Dictionary<int, double>();
 Dictionary<int, double> cellsFourth = new Dictionary<int, double>();
 Dictionary<int, double> cellsTotal = new Dictionary<int, double>();
 List<List<int>> allCells = new List<List<int>>();
 
 bool other = false;
 int z = 2;
 double val2 = 0.0;
 
 var val3 = 0.0;
 
 string message = "";
 
 List<string> years = new List<string>();
 
 for (int j=0; j<Matrix1.ResultTable.RowCount; j++)
 {
 var column = Matrix1.ResultTable.Columns[0] as TableColumn;
 try
 {
 years.Add(Matrix1.ResultTable.GetCellData(0,j).Value.ToString());
 }
 catch (Exception)
 {}
 } 
 
 //wir führen Zyklen für jedes Jahr
 foreach (var year in years)
 {
 total = false;
 //wir bekommen Zellwerte für jedes Jahr nach der angegebenen Spalte 
 while (!total)
 {
 //Total aus der Liste der sortierten Werte ausschließen
 if (Matrix1.ResultTable.GetCellData(1,z).Text!="Total")
 {
 //Monatsspalte
 var value = Matrix1.ResultTable.GetCellData(1,z).Value;
 if (value!=null)
 {
 Double.TryParse(value.ToString(),out val3);
 cellsMonth.Add(z,val3);
 }
 else
 cellsMonth.Add(z, 0.0);
 
 //Spalte für den ersten Mitarbeiter
 value = Matrix1.ResultTable.GetCellData(2,z).Value;
 if (value!=null)
 {
 Double.TryParse(value.ToString(),out val3);
 cellsFirst.Add(z,val3);
 }
 else
 cellsFirst.Add(z, 0.0);
 
 //Spalte für den zweiten Mitarbeiter
 value = Matrix1.ResultTable.GetCellData(3,z).Value;
 if (value!=null)
 {
 Double.TryParse(value.ToString(),out val3);
 cellsSecond.Add(z,val3);
 }
 else
 cellsSecond.Add(z, 0.0);
 
 //Spalte für den dritten Mitarbeiter
 value = Matrix1.ResultTable.GetCellData(5,z).Value;
 if (value!=null)
 {
 Double.TryParse(value.ToString(),out val3);
 cellsFourth.Add(z,val3);
 }
 else
 cellsFourth.Add(z, 0.0);
 
 //Sortierbare Spalte. Dient als Sortieretalon für alle anderen
 value = Matrix1.ResultTable.GetCellData(4,z).Value;
 if (value!=null)
 {
 Double.TryParse(value.ToString(),out val3);
 cellsThird.Add(z,val3);
 }
 else
 cellsThird.Add(z, 0.0);
 
 //Spalte für den fünften Mitarbeiter
 value = Matrix1.ResultTable.GetCellData(6,z).Value;
 if (value!=null)
 {
 Double.TryParse(value.ToString(),out val3);
 cellsTotal.Add(z,val3);
 }
 else
 cellsTotal.Add(z, 0.0);
 }
 else
 {
 total = true;
 } 
 z++;
 } 
 
 //Sortieren nach cellsThird - Spalte für den dritten Mitarbeiter
 var keys = cellsThird.OrderByDescending(i=>i.Value).Select(key => key.Key).ToList();
 
 //Setzen eines neuen Wertes für Zellen in allen Zeilen in den gewünschten Spalten entsprechend der Reihenfolge im sortierten Wörterbuch für die dritte Spalte
 int k = 0;
 foreach(var key in keys)
 {
 Matrix1.ResultTable.GetCellData(1, cellsThird.Keys.ElementAt(k)).Text = cellsMonth[key].ToString();
 Matrix1.ResultTable.GetCellData(2, cellsThird.Keys.ElementAt(k)).Text = cellsFirst[key].ToString();
 Matrix1.ResultTable.GetCellData(3, cellsThird.Keys.ElementAt(k)).Text = cellsSecond[key].ToString();
 Matrix1.ResultTable.GetCellData(4, cellsThird.Keys.ElementAt(k)).Text = cellsThird[key].ToString();
 Matrix1.ResultTable.GetCellData(5, cellsThird.Keys.ElementAt(k)).Text = cellsFourth[key].ToString();
 Matrix1.ResultTable.GetCellData(6, cellsThird.Keys.ElementAt(k)).Text = cellsTotal[key].ToString();
 k++;
 }
 cellsThird.Clear();
 }
 }
 }

Es gibt zwei grundsätzliche Unterschiede zur vorherigen Methode - wir sortieren mit Ersetzung statt mit Löschen/Einfügen und sortieren nach jeder Spalte separat.

Aus Kommentaren im Code sollte ersichtlich sein, was und wo passiert. Aber lassen wir uns das kurz betrachten:

1) Zuerst erhalten wir die Werte der Messgruppen, damit wir wissen, wie viele Sortiersätze wir benötigen. Jede Gruppe hat ihre eigene Sortierreihenfolge.
2) Als nächstes erhalten wir die Daten für alle Spalten, die wir für die Sortierung benötigen. Damit sind alle Spalten gemeint, außer der ersten, die die Namen der Messgruppen enthält.
3) Wählen wir dann einen Satz von Werten, die für die Sortierung benötigt werden, und sortieren wir ihn.
4) Mit Hilfe des resultierenden Wörterbuchs, bei dem der Schlüssel ein Index einer Zelle ist, kann man Zellen in allen Spalten aneinanderreihen, die nach der Reihenfolge dieser Indizes sortiert sind.

Das Ergebnis ist eine sortierte Matrix für Nancy Davolio:

Matrix sortiert nach Spalte für Mitarbeiterin Nancy Davolio

Auf diese Weise können Sie eine Matrix nach einer beliebigen Spalte von Daten sortieren. Darüber hinaus können Sie eine benutzerdefinierte Sortierung vornehmen - nicht nur in absteigender oder aufsteigender Reihenfolge. Zusätzlich kann man bestimmte Zeilen von der Sortierung ausschließen (Total oder berechnet), indem Sie deren individuelle Reihenfolge festlegen.

1. November 2024

Neue Funktionen des FastReport VCL Berichtseditors

Wir betrachten die neuen Funktionen des Berichtseditors: Hilfslinien, Hervorhebung von sich schneidenden Objekten, aktualisierte Berichts- und Datenbäume.
30. Oktober 2024

Verwendung von Stilen beim Erstellen von Berichten in FastReport VCL

Dieser Artikel beschreibt eine der neuen Funktionen von FastReport VCL - die Verwendung von Stilen und Stilseiten.
28. Oktober 2024

WSL 2 Anpassung an FastReport und FastCube

In diesem Artikel werden wir versuchen, gemeinsam herauszufinden, wie man WSL 2 konfiguriert, um mit FastReport und FastCube Komponenten in Lazarus für Linux zu arbeiten.
Fast Reports
  • 800-985-8986 (Englisch, die USA)
  • +4930568373928 (Deutsch)
  • +55 19 98147-8148 (Portugiesisch)
  • info@fast-report.com
  • 66 Canal Center Plaza, Ste 505, Alexandria, VA 22314

© 1998-2024 Fast Reports Inc.