Entwickler-Ecke
Basistechnologien - Excel File auslesen und in Array abspeichern
sebastian1234 - Do 02.01.14 15:46
Titel: Excel File auslesen und in Array abspeichern
Hallo zusammen,
ich muss ein Excel File auslesen und dieses anschließend in meinem Programm in double oder int in einem Array ablegen das weiter verarbeitet wird.
Folgendes habe ich bisher programmiert. Ich kann das Excel File bereits auslesen und in einem Datagrid darstellen.
C#-Quelltext
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:
| public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void ChooseFile_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog1 = new OpenFileDialog(); if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK) { this.textBox1.Text = openFileDialog1.FileName; } }
private void AuswahlTabelle_Click(object sender, EventArgs e) { string PathConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + textBox1.Text + ";Extended Properties=\"Excel 8.0;HDR=Yes;\";"; OleDbConnection conn = new OleDbConnection(PathConn);
OleDbDataAdapter myDataAdapter = new OleDbDataAdapter("Select * from [" + textBox2.Text + "$]", conn); DataTable dt = new DataTable();
myDataAdapter.Fill(dt); dataGridView1.DataSource = dt;
DataSet kt = new DataSet(); double[][] kunde = new double[2][]; }
} } |
Es handelt sich um ein einfaches Excel File mit jeweils 3 Spalten und Zeilen! Allerdings kann möglichweise eine Spalte hinzukommen. Besteht die Möglichkeit das die einzelnen Spalten und Zeilen dann "flexible" in ein Array gespeichert werden?
Darüberhinaus soll nach in der Oberfläche die Möglichkeit einer Spaltenauswahl bestehen. D.h. das der User auswählen kann welche Spalte berücksichtigt werden und somit in das Array übernommen werden sollen. Wie würdet ihr hier vorgehen? Ich würde mich über kleine Tipps sehr freuen...
Vielen Dank und viele grüße
Moderiert von
Christian S.: Quote- durch C#-Tags ersetztModeriert von
Christian S.: Beiträge zusammengefasstÜber den OleDb kann ich ja auf jeden Fall schonmal die Daten auslesen. Aber wie werden die Werte jetzt in ein Array (oder vielleicht etwas anderes) gespeichert, damit diese Werte nachher verrechnet werden können...
Ralf Jansen - Do 02.01.14 16:30
Zitat: |
Es handelt sich um ein einfaches Excel File mit jeweils 3 Spalten und Zeilen! Allerdings kann möglichweise eine Spalte hinzukommen. Besteht die Möglichkeit das die einzelnen Spalten und Zeilen dann "flexible" in ein Array gespeichert werden? |
z.B.
C#-Quelltext
1:
| double[][] kunde = dt.Rows.OfType<DataRow>().Select(x => x.ItemArray.Cast<double>().ToArray()).ToArray(); |
Zitat: |
Darüberhinaus soll nach in der Oberfläche die Möglichkeit einer Spaltenauswahl bestehen. D.h. das der User auswählen kann welche Spalte berücksichtigt werden und somit in das Array übernommen werden sollen. Wie würdet ihr hier vorgehen? Ich würde mich über kleine Tipps sehr freuen... |
Das Connection Object OleDbConnection hat eine GetSchema Methode da kannst du dir für alle Tabellen die Spalteninfo ranholen durcharbeiten und die möglichen Spalten dann zur Auswahl anbieten.
Mit den dann ausgewählten Spalten kannst du denn Linqausdruck entsprechend anpassen.
C#-Quelltext
1:
| double[][] kunde = dt.Rows.OfType<DataRow>().Select(x => new double[] { (double)x["A"], (double)x["B"] }).ToArray(); |
Edit: Das letzte was Unsinn. Ich vergaß das es von selbst kein dynamisches Linq gibt.
Was funktioniert ist sich die Indizes der ausgewählten Spalten zu merken. Die kann man leicht vergleichen ohne dynamischen Code zu brauchen.
C#-Quelltext
1: 2:
| double[] selectedRowIndices = { 0, 2 }; int[][] kunde = dt.Rows.OfType<DataRow>().Select(x => x.ItemArray.Cast<double>().Where((v,i) => selectedRowIndices.Contains(i)).ToArray()).ToArray(); |
Edit 2:
Zitat: |
Über den OleDb kann ich ja auf jeden Fall schonmal die Daten auslesen. Aber wie werden die Werte jetzt in ein Array (oder vielleicht etwas anderes) gespeichert, damit diese Werte nachher verrechnet werden können... |
Wenns kein Array sein muß dann nimm halt die DataTable die du schon hast.
sebastian1234 - Do 02.01.14 18:24
Vielen Dank Ralf!
Das auslesen der Excel Tabelle klappt, allerdings nimmt er nicht alle Spalten! Damit du auch genau verstehst was ich eigentlich mache kurz noch eine wichtige Info. Ich entwickle zunächst ein Programm das Euklidische Distanzen zwischen verschiedenen Werte berechnet.
Ausgangspunkt war bisher diese Klasse mit folgendem Array. Dieses "Array" bzw die Werte habe ich 1:1 in das Excel File gelegt!
Dieses Array wurde in folgender Methode zur Berechnung der Distanzmaße angewendet...
C#-Quelltext
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:
| static void distanzBerechnung(double[][] kunde) { for (int a = 0; a < kunde.Length; ++a) { Console.WriteLine(kunde[a][0]);
for (int b = 0; b < kunde.Length; ++b) { for (int p = 1; p <= 1; ++p) { for (int q = 2; q <= 2; ++q) { double Formel = 0; Formel = Math.Sqrt(Math.Pow(kunde[a][p] - kunde[b][p], 2) + Math.Pow(kunde[a][p] - kunde[b][p], 2)); Console.WriteLine(Formel); } } } } } |
Wenn ich nun deine Abfrage verwende...
C#-Quelltext
1:
| double[][] kunde = dt.Rows.OfType<DataRow>().Select(x => x.ItemArray.Cast<double>().ToArray()).ToArray(); |
Gibt er mir allerdings nur die Spalte A und B der Excel Tabelle aus. Dadurch ist die Distanzberechnung natürlich unvollständig. Ich bin noch nicht auf die Lösung des Problems gekommen...
Trotzdem vielen vielen Dank! Endlich komme ich mit meinem Programm wieder etwas weiter =)
Th69 - Do 02.01.14 18:42
Hallo und :welcome:
die Übergabe an das Array wird einwandfrei funktionieren, nur ist deine Auswertung innerhalb deiner Methode distanzBerechnung fehlerbehaftet:
- du greifst bisher nur auf p zu (nicht auf q)!
- die beiden for-Schleifen mit p und p sind überflüssig
sebastian1234 - Fr 03.01.14 16:07
Okay du hast Recht das hatte ich total übersehen! Ich habe es jetzt so abgeändert...
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| static void distanzBerechnung(double[][] kunde) { for (int a = 0; a < kunde.Length; ++a) { Console.WriteLine(kunde[a][0]);
for (int b = 0; b < kunde.Length; ++b) { int p = 1; int q = 2; int t = 3; double Formel = 0; Formel = Math.Sqrt(Math.Pow(kunde[a][p] - kunde[b][p], 2) + Math.Pow(kunde[a][q] - kunde[b][q], 2) + Math.Pow(kunde[a][t] - kunde[b][t], 2)); Console.WriteLine(Formel); } } } |
Wie ich oben schon angesprochen habe, muss ich eine Auswahlmöglichkeit bauen die mir ermöglicht, gewisse Spalten auszuwählen, sodass nur die ausgewählten Spalten in die Distanzberechnung mit eingehen.
So sieht die Excel Tabelle bzw. das DataGrid aus:
ID / Kennzahl1 / Kennzahl2 / Kennzahl3
1 / 10 / 20 / 15
2 / 25 / 45 / 35
3 / 45 / 55 / 85
Ich habe gesehen das man im DataGrid die Spalten markieren bzw. auswählen kann. Darüber kann man doch dann bestimmt eine solche Auswahlmöglichkeit realisieren. Also das nur die Makierten Spalten an das Array und dann die Distanzberechnung übergeben werden.
Eine andere Lösung könnte vielleicht das Anlegen einer CheckedListBox sein, die dann die Spaltenüberschriften der Tabelle ausließt und in der man dann jeweils die Spalten auswählen kann (bsp. Kennzahl1 und Kennzahl2)
Welchen Weg würde sich hier am besten anbieten.
Viele Grüße
sebastian1234 - Fr 03.01.14 18:04
Kurze Ergänzung!
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
| private void AuswahlButton_Click(object sender, EventArgs e) { string PathConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + textBox1.Text + ";Extended Properties=\"Excel 8.0;HDR=Yes;\";"; OleDbConnection conn = new OleDbConnection(PathConn); OleDbCommand cmd = new OleDbCommand("Select column_name from [" + "Tabelle1" + "$]", conn); OleDbDataReader dr;
dr = cmd.ExecuteReader(); if (dr.HasRows) { while (dr.Read()) { checkedListBox1.Items.Add(dr[0].ToString()); } } dr.Close(); conn.Close(); } |
Um die oberste Reihe zur Auswahl der Spalten zu erhalten habe ich column_name genommen! Allerdings bin ich mir nicht sicher ob das wirklich funktioniert!
Die oberste Spaltenname sollen in der checkboxliste ausgegeben werden und darüber ausgewählt werden können.
Aktuelle erhalte ich beim Ausführen den Fehler "INvalidOperationException" bei dr. = cmd.ExecuteReader();
Ralf Jansen - Fr 03.01.14 18:33
Ich zitier mich mal selbst.
Ralf Jansen hat folgendes geschrieben : |
Das Connection Object OleDbConnection hat eine GetSchema Methode da kannst du dir für alle Tabellen die Spalteninfo ranholen durcharbeiten und die möglichen Spalten dann zur Auswahl anbieten. |
Das was du vor hattest ist irgendwie merkwürdig. Die Spaltennamen in deiner Tabelle stehen in einer Row und nicht in einer Column. Wo hast du das her mit column_name?
sebastian1234 - Fr 03.01.14 18:39
Mein Beispiel basiert auf dem SQL Client! Ich dachte ich könnte das irgendwie mit OleDB verbinden bzw. einbauen. Ok das scheint nicht zu gehen.
Dann werde ich mir mal das GetSchema von OleDbConnection anschauen...
sebastian1234 - Mo 06.01.14 13:01
Ich habe mich am Wochenende mal mit OleDbConnection get Schema auseinander gesetzt und folgendes gebaut (in der Methode AuswahlButton_CLick)...
C#-Quelltext
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:
| using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Data.OleDb;
namespace Clusteranalyse { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void ChooseFile_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog1 = new OpenFileDialog(); if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK) { this.textBox1.Text = openFileDialog1.FileName; } }
private void AuswahlTabelle_Click(object sender, EventArgs e) { string PathConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + textBox1.Text + ";Extended Properties=\"Excel 8.0;HDR=Yes;\";"; OleDbConnection conn = new OleDbConnection(PathConn);
OleDbDataAdapter myDataAdapter = new OleDbDataAdapter("Select * from [" + "Tabelle1" + "$]", conn); DataTable dt = new DataTable();
myDataAdapter.Fill(dt); dataGridView1.DataSource = dt;
double[][] kunde = dt.Rows.OfType<DataRow>().Select(x => x.ItemArray.Cast<double>().ToArray()).ToArray(); distanzBerechnung(kunde);
}
static void distanzBerechnung(double[][] kunde) { for (int a = 0; a < kunde.Length; ++a) { Console.WriteLine(kunde[a][0]);
for (int b = 0; b < kunde.Length; ++b) { int p = 1; int q = 2; int t = 3; double Formel = 0; Formel = Math.Sqrt(Math.Pow(kunde[a][p] - kunde[b][p], 2) + Math.Pow(kunde[a][q] - kunde[b][q], 2) + Math.Pow(kunde[a][t] - kunde[b][t], 2)); Console.WriteLine(Formel); } } }
private void AuswahlButton_Click(object sender, EventArgs e) { OleDbConnection conn = new OleDbConnection(); OleDbCommand cmd = new OleDbCommand(); DataTable schemaTable; OleDbDataReader myReader;
conn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + textBox1.Text + ";Extended Properties=\"Excel 8.0;HDR=Yes;\";"; conn.Open();
cmd.Connection = conn; cmd.CommandText = "Select * from [" + "Tabelle1" + "$]"; myReader = cmd.ExecuteReader(CommandBehavior.KeyInfo);
schemaTable = myReader.GetSchemaTable();
foreach (DataRow myField in schemaTable.Rows) { foreach (DataColumn myProperty in schemaTable.Columns) { Console.WriteLine(myProperty.ColumnName + " = " + myField[myProperty].ToString()); } Console.WriteLine(); Console.ReadLine(); }
myReader.Close(); conn.Close(); } } } |
Ich möchte mir zunächst über die Methode AuswahlButton_Click, die Spaltennamen über die Console ausgeben lassen und damit nachher die Auswahl durchzuführen. Allerdings erhalte ich momentan 2 Fehler!
1.Fehler
Quelldatei: .... /Clusteranalyse/Form1.cs
Modul: .... /bin/debug/Clusteranalyse.exe
Prozess: [2576] Clusteranalyse.vshost.exe
Die Quelldatei ist anders als zum Zeitpunkt der Erstellung des Moduls. Soll der Debugger sie dennoch verwenden? ja/nein
2.Fehler
conn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + textBox1.Text + ";Extended Properties=\"Excel 8.0;HDR=Yes;\";";
InvalidOperationException -> Execute Reader erfordert eine geöffnete und verfügbare Verbindung. Aktueller Status geschlossen!
Mir ist nicht ganz klar weshalb die Verbindung geschlossen ist? Über conn.open(); öffne ich sie doch?!
Mein Programm ist bisher auch sehr provisorisch aufgebaut. So gibt es noch die ursprungs Klasse welche nur noch ein Objekt vom Typ form öffnet
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| namespace Clusteranalyse { class DistanzenBerechnen { [STAThread] static void Main(string[] args) {
Form1 dialog = new Form1(); dialog.ShowDialog();
} |
Kann einer erkenne wo ich einen Fehler mache?
Viele Grüße!
sebastian1234 - Do 09.01.14 16:10
Hallo,
nachdem ich das Programm nochmals neue 1:1 programmiert habe erhalt ich nun eine Ausgabe!
Allerdings werde eine ganz Reihe verschiedener Informationen in der Konsole veröffentlicht.
ColumnName = ID
ColumnOrdinal = 0
ColumnSize = 8
NumericPrecision = 15
NumericScale = 0
DataType = System.double
ProviderType= 5
usw...
Meine Excel Tabelle besteht ja aus den Spalten ID/Kennzahl1/Kennzahl2/Kennzahl3 und nur diese Spalten sollten ausgegeben werden, sodass später eine Auswahl nach diesen Spalten gemacht werden kann.
C#-Quelltext
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:
| private void AuswahlButton_Click(object sender, EventArgs e) { OleDbConnection conn = new OleDbConnection(); OleDbCommand cmd = new OleDbCommand(); DataTable schemaTable; OleDbDataReader myReader;
conn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + textBox1.Text + ";Extended Properties=\"Excel 8.0;HDR=Yes;\";"; conn.Open();
cmd.Connection = conn; cmd.CommandText = "Select * from [" + "Tabelle1" + "$]"; myReader = cmd.ExecuteReader(CommandBehavior.KeyInfo);
schemaTable = myReader.GetSchemaTable();
foreach (DataRow myField in schemaTable.Rows) { foreach (DataColumn myProperty in schemaTable.Columns) { Console.WriteLine(myProperty.ColumnName + " = " + myField[myProperty].ToString()); } Console.WriteLine(); Console.ReadLine(); }
myReader.Close(); conn.Close(); } } |
Ich denke das Problem liegt irgendwie in der foreach-Schleife?!
sebastian1234 - Do 09.01.14 17:32
Ohja du das stimmt!
Ich habe jetzt diese Lösung gebaut und sie funktioniert!
C#-Quelltext
1: 2: 3: 4: 5:
| foreach (DataRow myField in schemaTable.Rows) { string sColumnName = myField["ColumnName"].ToString(); checkedListBox1.Items.Add(sColumnName); } |
Allerdings kommt jetzt der wohl komplizierte Teil.
Wie schaffe ich es das Array so zu beeinflussen das nur die Ausgewählten Felder mit einbezogen werden?
Irgendwie muss die Auswahl ja mit in die OleDbCommand Anweisung. Also das quasi nur die ausgewählten Spalten berücksichtigt werden?! Das * hinter SELECT müsste doch irgendwie angepasst werden?
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| OleDbDataAdapter myDataAdapter = new OleDbDataAdapter("Select * from [" + "Tabelle1" + "$]", conn); DataTable dt = new DataTable();
myDataAdapter.Fill(dt); dataGridView1.DataSource = dt;
double[][] kunde = dt.Rows.OfType<DataRow>().Select(x => x.ItemArray.Cast<double>().ToArray()).ToArray(); distanzBerechnung(kunde); |
Vielen Dank
Ralf Jansen - Do 09.01.14 18:23
Nimm dir die selektierten Einträge aus deiner CheckListBox und schreib die kommasepariert anstelle des * in die Abfrage.
sebastian1234 - Do 09.01.14 18:47
Ich möchte das dynamisch machen. Also das ich in meiner Oberfläche die einzelnen Spalten auswählen kann. Wenn ich die Spaltennamen jetzt einfach in die Abfrage schreibe ist das ja nicht möglich. Oder habe ich das falsch verstanden?
...
Kann man die ausgewählten Spalten nicht durch drücken eines Buttons in ein Array schreiben und dieses dann in die Abfrage anstelle von * integrieren?
Ralf Jansen - Do 09.01.14 18:52
Ja? Zur Laufzeit liest du die gerade selektierten Einträge aus der Listbox und schreibst die Liste an die Stelle wo im Moment noch der * steht. Was in einen string einfügen solltest du hinbekommen hast du ja mit dem Sheet-Namen auch geschafft.
sebastian1234 - Do 09.01.14 20:24
Ich habe mal was probiert allerdings bin ich langsam mit meinem Latein am Ende.
Hiermit wollte ich mir die ausgewählten Spalten ausgeben lassen aber irgendwie gibt er mir die nciht wirklich zurück.
C#-Quelltext
1:
| checkedListBox1.getitemText(CheckedListBox1.CheckedItems); |
Button1 = Ließt die Spalten aus dem Excel File und zeigt sie mir in der Checkedlist box an.
Über Button2 = Sollen nun die ausgewählten Spalten in das Array gespeichert werden....
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| private void AuswahlTabelle_Click(object sender, EventArgs e) { string PathConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + textBox1.Text + ";Extended Properties=\"Excel 8.0;HDR=Yes;\";"; OleDbConnection conn = new OleDbConnection(PathConn);
OleDbDataAdapter myDataAdapter = new OleDbDataAdapter("Select * from [" + "Tabelle1" + "$]", conn); DataTable dt = new DataTable();
myDataAdapter.Fill(dt); dataGridView1.DataSource = dt;
double[][] kunde = dt.Rows.OfType<DataRow>().Select(x => x.ItemArray.Cast<double>().ToArray()).ToArray(); distanzBerechnung(kunde); |
Kennst du vielleicht ein ähnliches Beispiel an dem ich mich orientierten kann?
Ralf Jansen - Do 09.01.14 21:29
Das mit getitemText wird dir nicht weiterhelfen. Du hast ja die Texte vermutlich direkt in die CheckedListBox geschrieben damit enthält die CheckedItems einfach eine Liste von strings. Das muß man dem Compiler nur klar machen. Das geht zum Beispiel mit der Extension Method OfType<T>. Wenn du dann eine Liste von strings hast kannst du die mit string.Join und einem Trennzeichen zusammenfügen.
Also etwa
C#-Quelltext
1:
| string meineLiebenColumns = string.Join(",", checkedListBox1.CheckedItems.OfType<string>()); |
und dann das eben als Spaltenliste in deinen SQL String einbauen. Etwa
C#-Quelltext
1: 2:
| string meinLiebesSQLStatement = string.Format("select {0} from [{1}$]", meineLiebenColumns , meinLieberSheetName); OleDbDataAdapter myDataAdapter = new OleDbDataAdapter(meinLiebesSQLStatement , conn); |
sebastian1234 - Sa 11.01.14 13:30
Hallo Ralf,
ich verstehe jetzt wie das funktioniert aber ich habe mich vorher etwas ungenau ausgedrückt.
Hier jetzt nochmal das vollständige Programm!
Ich geh mal schnell die Methoden durch:
1.choose_File Click: wählt die Datei aus!
2.Auswahl_tabelle Click: Holt die Daten aus dem Excel File, stellte diese im DataGrid an der oberfläche dar und Berechnet dann die Distanzen
3.distanz_Berechnung: Berechnet die Distanzen
4.Auswahl_button Click: ließt die Spaltendaten aus dem Excel File und läd sie in das checklistbox feld!
Ich möchte nun die Methode 2 und 4 quasi zu einer machen! Die Spaltenname werden zur Laufzeit über den Auswahl_Button Click in das checkedlistbox Feld geladen und stehen nciht vorher schon drin! auf Basis der Auswahl soll dann so weitergerechnet werden wie in methode 1!
ich habe
C#-Quelltext
1:
| string meineLiebenColumns = string.Join(",", checkedListBox1.CheckedItems.OfType<string>()); |
irgendwie versucht mal in die 4.methode einzubauen um damit die ausgewählten spalten werte aus der checkedlistbox zu erhalten aber irgendwie wird immer ein fehler angezeigt...
C#-Quelltext
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:
| using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Data.OleDb;
namespace Clusteranalyse { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void ChooseFile_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog1 = new OpenFileDialog(); if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK) { this.textBox1.Text = openFileDialog1.FileName; } }
private void AuswahlTabelle_Click(object sender, EventArgs e) { string PathConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + textBox1.Text + ";Extended Properties=\"Excel 8.0;HDR=Yes;\";"; OleDbConnection conn = new OleDbConnection(PathConn);
OleDbDataAdapter myDataAdapter = new OleDbDataAdapter("Select * from [" + "Tabelle1" + "$]", conn); DataTable dt = new DataTable();
myDataAdapter.Fill(dt); dataGridView1.DataSource = dt;
double[][] kunde = dt.Rows.OfType<DataRow>().Select(x => x.ItemArray.Cast<double>().ToArray()).ToArray(); distanzBerechnung(kunde); }
static void distanzBerechnung(double[][] kunde) { for (int a = 0; a < kunde.Length; ++a) { Console.WriteLine(kunde[a][0]);
for (int b = 0; b < kunde.Length; ++b) { int p = 1; int q = 2; int t = 3; double Formel = 0; Formel = Math.Sqrt(Math.Pow(kunde[a][p] - kunde[b][p], 2) + Math.Pow(kunde[a][q] - kunde[b][q], 2) + Math.Pow(kunde[a][t] - kunde[b][t], 2)); Console.WriteLine(Formel); } } }
private void AuswahlButton_Click_1(object sender, EventArgs e) { OleDbConnection conn = new OleDbConnection(); OleDbCommand cmd = new OleDbCommand(); DataTable schemaTable; OleDbDataReader myReader;
conn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + textBox1.Text + ";Extended Properties=\"Excel 8.0;HDR=Yes;\";"; conn.Open();
cmd.Connection = conn; cmd.CommandText = "Select * from [" + "Tabelle1" + "$]"; myReader = cmd.ExecuteReader(CommandBehavior.KeyInfo);
schemaTable = myReader.GetSchemaTable();
foreach (DataRow myField in schemaTable.Rows) { string sColumnName = myField["ColumnName"].ToString(); checkedListBox1.Items.Add(sColumnName); }
myReader.Close(); conn.Close(); } } } |
Wie würdest du die Methoden 2 und 4 zusammenlegen sodass mein Problem gelöst wird? Bzw. was verstehe ich nicht oder mache ich falsch, dass ich die ausgewählten Items der checkedlistbox nicht erhalte?
EDIT:
In der foreach Mehtoden müsste irgendwie etwas rein das quasi bei jedem Durchlauf die Spaltenname speichert ... ?
Th69 - Sa 11.01.14 13:45
Hallo sebastian1234,
sebastian1234 hat folgendes geschrieben: |
aber irgendwie wird immer ein fehler angezeigt... |
Welchen genauen Fehler erhältst du denn?
Arbeitest du noch mit .NET 3.5 (oder tiefer)? Dann fehlt noch ein
.ToArray() beim 2. Parameter von
String.Join (da die Überladung mit IEnumerable<T> noch nicht existiert).
Du solltest - in deinem eigenen Interesse - lernen, Fehlermeldungen interpretieren zu können, um diese selbständig zu lösen (d.h. evtl. im Internet danach zu suchen oder in der MSDN nachzuschlagen etc.).
sebastian1234 - Sa 11.01.14 13:53
Wahrscheinlich tiefer denn jetzt geht es! Allerdings gibt er mir immer noch nicht die Spalten aus sondern nur <Auflistung> <Auflistung> <Auflistung> <Auflistung>!
Ich versuche schon im Internet Lösung zu finden aber ich komme da momentan immer sehr schnell an meine Grenzen!
Aber wieso mir immer nur <Auflistung> ausgegeben wird verstehe ich nicht???
Moment jetzt scheint es zu klappen!!!!
sebastian1234 - Sa 11.01.14 14:01
Dadurch das ich den String in der Schleife ausgebe wird der natürlich, je nach Auswahl 4 mal angezeigt!
Wie schaffe ich es das in den String Wert lediglich nur einmal die Auswahl gespeichert wird, damit ich den String an die SQL Abfrage weitergeben kann?
EDIT: Habe es mit einer übergeordneten Variable gelöst!!!
sebastian1234 - Mo 13.01.14 12:12
Also mein Programm ist jetzt eigentlich soweit fertig! Das gesamte Projekt geht allerdings noch weiter =)
Es gibt nur noch eine Sache die im Programm gemacht werden muss! Und zwar handelt es sich um folgende Methode...
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| public static void distanzBerechnung(double[][] kunde) { for (int a = 0; a < kunde.Length; ++a) { Console.WriteLine(kunde[a][0]);
for (int b = 0; b < kunde.Length; ++b) { int p = 1; int q = 2; int t = 3; double Formel = 0; Formel = Math.Sqrt(Math.Pow(kunde[a][p] - kunde[b][p], 2) + Math.Pow(kunde[a][q] - kunde[b][q], 2) + Math.Pow(kunde[a][t] - kunde[b][t], 2)); Console.WriteLine(Formel); } } } |
In dieser Methode sind aktuell 3 Variablen (q,p,t) angegeben! Wenn ich über die Auswahl im Programm 3 Variablen auswähle wird die Methode ohne Probleme ausgeführt. Wähl ich allerdings nur 2 Variablen aus kommt es zu einem Fehler! Außerdem kann es in Zukunft sein das nicht nur 3 sondern bis zu 9 Variablen verwendet werden, von denen man unterschiedliche viele auswählen kann. Das Excel File besteht aus den Spaltenwerten ID / Kennzahl1 / Kennzahl2 / Kennzahl 3 usw...
Wie muss ich die Methode umbauen, damit ich beliebig viele Spalten bzw. Variablen auswählen kann und die Berechnung ohne einen Fehler korrekt durchläuft und dies nach der oben angegebenen Formel?
Ich würde mich über eine Tipp oder eine Idee sehr freuen mit der ich mich dann heute auseinandersetzten kann um eine Lösung zu bauen!
Viele Grüße...
Ralf Jansen - Mo 13.01.14 12:53
Deine Formel ist für 3 Dimensionen hart kodiert. Also must du die für beliebige Dimensionen umschreiben.
Du wirst also eine Schleife über die Anzahl Dimensionen brauchen der den Teil der jetzt explizit für p,q,t erfolgt einmal in der Schleife für die dann aktuelle Dimension berechnet und zu den bisherigen in der Schleife berechneten Werten hinzuaddiert. Nach der Schleife dann noch die Quadratwurzel aus diesem Wert ziehen.
sebastian1234 - Mo 13.01.14 15:23
Okay also ich habe folgendes gebaut...
C#-Quelltext
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:
| public static void distanzBerechnung(double[][] kunde) { double Ergebnis = 0; double Formel = 0; for (int a = 0; a < kunde.Length; ++a) { Console.WriteLine(kunde[a][0]);
for (int b = 0; b < kunde.Length; ++b) { for (int i = 1; i < kunde.Length; ++i) { Formel = (Math.Pow(kunde[a][i] - kunde[b][i],2)); Ergebnis += Formel; } double Endergebnis = 0; Endergebnis = Math.Sqrt(Ergebnis); Console.WriteLine(Endergebnis);
} } } |
Ich denke von der Grundidee sollte es richtig sein. Aber ich erhalte im Gegensatz zu vorher bei der Berechnung irgendwie falsche Werte. Kann mir das bisher nicht genau erklären!
Liegt das vielleicht daran das die Berechnung und Ausgabe in der falschen Schleife sind?!
Ralf Jansen - Mo 13.01.14 15:24
Warum fängt die Schleife bei 1 an?
sebastian1234 - Mo 13.01.14 15:37
Das Excel File hat die Spalten ID / Kennzahl1 / Kennzahl2 / Kennzahl3 usw
Die ID steht für einen bestimmten Fall und für die Berechnung der Distanzen benötigt man ja lediglich die Kennzahlenwerte.
i = 0; wäre ja dann ID aber die soll nicht mit in die Berechnung rein!
Also ist i = 1 doch eigentlich korrekt oder?
Ralf Jansen - Mo 13.01.14 15:43
Nein in dem Array sind nur noch die relevanten Daten. Zumindest wenn du das so programmiert hast wie hier besprochen. Nur die ausgewählten Spalten werden in das Array kopiert. Die Spaltenpositionen im Excelsheet haben also nix mehr zu tun mit denen im Array. Also wo sollte plötzlich in der ersten Dimension des Array die ID da reinkommen wenn du die da nicht hinkopiert hast?
sebastian1234 - Mo 13.01.14 15:46
Ich wähle in der checklistbox immer ID aus damit ich die Kennzahlen_Werte den einzelnen ID_Fällen zuordnen kann...
Ralf Jansen - Mo 13.01.14 15:49
Dann solltest du noch Formel und Ergebnis vor der inneren Schleife auf 0 zurücksetzen. Im Moment summierst du immer weiter auch wen du schon in der nächsten Zeile bist.
Edit: Falls das das Problem ist. Hätte ddir das beim debuggen des Codes auffallen müssen. Wenn nicht wäre es jetzt an der Zeit sich das Handwerk des Debuggens anzueignen. Ansonsten stehst du dir zu oft selbst im weg wenn du ein Problem durch blosses Ansehen des Codes finden willst. Das klappt üblicherweise nur ganz schlecht beim eigenen Code.
sebastian1234 - Mo 13.01.14 17:11
Okay! Ja du hattest auf jeden Fall recht! Das mit dem debuggen schau ich mir jetzt mal an!
Allerdings habe ich die Spaltenwerte nun von 3 auf 7 erhöht und hier ist mir aufgefallen das er bei 3 Schleifendurchgängen abbricht. Er verwendet vermutlich nur die Zeilenwerte die halt 3 sind. (3 Zeilenwerte)
In der for-Schleife müsste i aber 7 Durchläufe haben! Ist die for-Schleife für i falsch? Oder wie kann ich die Spaltenwerte über i auf die Spaltenanzahl erhalten?
Th69 - Mo 13.01.14 17:22
Hallo,
dann verwende kunde[a].Length oder kunde[b].Length (bzw. noch besser, das Minimum aus beiden Werten - falls die Zeilen unterschiedlich lang sind).
Ich hoffe dir ist klar, was da der Unterschied zu kunde.Length ist?
Ralf Jansen - Mo 13.01.14 17:25
kunde.Length ist die Länge der ersten Dimension die enthält die Zeilen (vermutlich hast du im Moment 3 Zeilen) du willst aber die Länge der Zweiten Dimension.
Korrekterweise müßtest du immer die Länge der aktuellen zeile von a oder b nehmen da ja zumindest theoretisch nicht jede Zeile gleich viele Spalten hat.
Da wir es aber besser Wissen könne wir einfach die Länge irgendeiner Zeile nehmen z.B einfach der ersten also kunde[0].Length.
Edit: Ich schwör ich wollt nicht vorsagen :angel:
sebastian1234 - So 02.02.14 15:02
Hallo zusammen,
die Anforderungen an mein Programm haben sich wieder etwas verändert! Ich habe auf der Oberfläche einen zusätzliche checkbox eingefügt. Über eine Methode die eine if else Abfrage beinhaltet soll nun über geben werden ob die checkbox gecheckt ist oder nicht! Allerdings kann ich in meiner DistanzBerechnen Klasse nicht darauf zugreifen sondern nur in der Form1 Klasse. Wie kann ich auch in meiner DistanzBerechne klasse darauf zugreifen?
Hier zunächst die Klasse in der ich auf die checkbox1 zugreifen kann...
C#-Quelltext
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:
| using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Data.OleDb;
namespace Clusteranalyse { public partial class Form1 : Form { string spalten; DistanzenBerechnen rechnen = new DistanzenBerechnen(); public Form1() { InitializeComponent(); } private void ChooseFile_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog1 = new OpenFileDialog(); if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK) { this.textBox1.Text = openFileDialog1.FileName; } }
public void AuswahlTabelle_Click(object sender, EventArgs e) { string PathConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + textBox1.Text + ";Extended Properties=\"Excel 8.0;HDR=Yes;\";"; OleDbConnection conn = new OleDbConnection(PathConn);
spalten = string.Join(",", checkedListBox1.CheckedItems.OfType<string>().ToArray()); Console.WriteLine("Geladene Spaltenwerte: "+spalten); Console.WriteLine("");
OleDbDataAdapter myDataAdapter = new OleDbDataAdapter("Select "+spalten+" from [" + "Tabelle1" + "$]", conn); DataTable dt = new DataTable();
myDataAdapter.Fill(dt); dataGridView1.DataSource = dt;
double[][] kunde = dt.Rows.OfType<DataRow>().Select(x => x.ItemArray.Cast<double>().ToArray()).ToArray(); DistanzenBerechnen.distanzBerechnung(kunde);
}
public void AuswahlButton_Click_1(object sender, EventArgs e) { OleDbConnection conn = new OleDbConnection(); OleDbCommand cmd = new OleDbCommand(); DataTable schemaTable; OleDbDataReader myReader;
conn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + textBox1.Text + ";Extended Properties=\"Excel 8.0;HDR=Yes;\";"; conn.Open();
cmd.Connection = conn; cmd.CommandText = "Select * from [" + "Tabelle1" + "$]"; myReader = cmd.ExecuteReader(CommandBehavior.KeyInfo);
schemaTable = myReader.GetSchemaTable(); foreach (DataRow myField in schemaTable.Rows) { string sColumnName = myField["ColumnName"].ToString(); checkedListBox1.Items.Add(sColumnName); } myReader.Close(); conn.Close(); } } } |
Und hier die Klasse in der es bisher nicht geht! Die Frage ist wie ich die Übergabe hinbekomme. ich setzte mich gerade mit Konstrukoren auseinander aber noch keine Lösung gefunden...
C#-Quelltext
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:
| using System; using System.Collections.Generic; using System.Linq; using System.Text;
namespace Clusteranalyse { public class DistanzenBerechnen { [STAThread] static void Main(string[] args) { Form1 dialog = new Form1(); dialog.ShowDialog(); }
public static void distanzBerechnung(double[][] kunde) { double Ergebnis = 0; double Formel = 0; for (int a = 0; a < kunde.Length; ++a) { Console.WriteLine(""); Console.WriteLine("Unternehmen: "+kunde[a][0]);
for (int b = 0; b < kunde.Length; ++b) { for (int i = 1; i < kunde[0].Length; ++i) { Formel = (Math.Pow(kunde[a][i] - kunde[b][i],2)); Ergebnis += Formel; }
} } }
public static void distanzBerechnungAuswahl(Ergebnis) { double Endergebnis = 0; if(checkBox1 == checked){ Endergebnis = Math.Sqrt(Ergebnis); Console.WriteLine(Endergebnis); Endergebnis = 0; } else{ Console.WriteLine("Hier wird City Block Metrik definiert!"); } } }
} |
Kleiner Tipp wäre sehr hilfreich! In die DistanzBerechnenAuswahl soll die Abfrage der checkbox hinkommen...
Viele Grüße und danke...
Moderiert von
Th69: Beiträge zusammengefasstEDIT: PROBLEM gelöst!!!
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!