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.
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:
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:
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:
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:
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.