mit Elementen eines Arrays rechnen und zu einem neuen Array zusammenfassen



  • Hallo,
    ich habe ein Problem, aber im Internet noch keinen Lösungsansatz gefunden. Bücher helfen leider auch nicht. Ich hoffe ihr könnt mir Helfen.

    Ich habe eine txt Datei mit 300x256 Elementen.
    Bisher habe ich es geschafft, diese Matrix in ein zweidimentionales Array zu speichern.

    Nun will ich aber damit arbeiten. Und zwar will ich es verkleinern mit folgenden Algorithmus

    Beispiel Matrix (aus Textdatei) - Array [4][8]
    1 1 2 2 3 3 4 4
    1 1 2 2 3 3 4 4
    5 5 6 6 7 7 8 8
    5 5 6 6 7 7 8 8

    Agorithmus:
    a=(1+1+1+1)/4
    b=(2+2+2+2)/4
    c=(3+3+3+3)/4
    d=(4+4+4+4)/4
    e=(5+5+5+5)/4
    f=(6+6+6+6)/4
    g=(7+7+7+7)/4
    h=(8+8+8+8)/4

    Beispiel Matrix verkleinert
    a b c d
    e f g h

    Beispiel Matrix neu - Array [2][4]
    1 2 3 4
    5 6 7 8

    das Problem ist, ich kenne die Inhalte der Textdatei nicht bzw. sind sie zu groß, um es für jedes einzelne Feld zu berechnen.
    Frage:
    1. wie kann ich den Algorithmus auf ein Array anwenden?
    2. Geht das überhaupt?

    Meine fkt zu dem erstelleten Array endet so:

    void save_ODatei() {
    
            int zeilen;
            int spalten;
    
            cout << " Bitte Zeilenanzahl der ausgelesenen Datei ein:";
            cin >> zeilen;
            cout << " Bitte Spaltenanzahl der ausgelesenen Datei ein:";
            cin >> spalten;
    
            int int_werte[zeilen][spalten];
            ifstream input("Test.txt");
            if(!input) {
            cout << "Die Datei wurde nicht gefunden." << endl;
            }
            // Daten Einlesen
            for(unsigned int x = 0; x != zeilen; ++x) {
                for(unsigned int y = 0; y != spalten; ++y) {
                    if(!input.eof()) {
                        input >> int_werte[x][y];
                    } else {
                        int_werte[x][y] = 0;
                      }
                }
            }
            input.close();
    }
    

    Vielen Dank schon mal fürs Überlegen 🙂



  • Anfaenger_braucht_Hilfe schrieb:

    Ich habe eine txt Datei mit 300x256 Elementen.

    Agorithmus:
    a=(1+1+1+1)/4
    Frage:
    1. wie kann ich den Algorithmus auf ein Array anwenden?
    2. Geht das überhaupt?

    Warum soll das nicht gehen. Der vorhandene Code funktioniert doch ?

    Ich würde den Speicher dynamisch besorgen; auch weil diverse Compiler "dynamische statische Arrays" nicht unterstützen.

    // Speicher besorgen
    int** myarr = new int*[spalten+(spalten%2)];
    for(int i = 0; i < spalten; ++i)
      myarr[i] = new int[zeilen+(zeilen%2)];
    

    Wobei es üblich ist Spalten mit x und Zeilen mit y zu bezeichnen. Und formal
    muss das Feld auch eine gerade Anzahl Zeilen u. Spalten haben.

    Nach dem einlesen kann man mit dem Feld rechnen, wo soll das Problem sein ?

    for(unsigned int y = 0; y != zeilen; y+=2) { 
      for(unsigned int x = 0; x != spalten; x+=2) { 
        int a=(myarr[x][y] + myarr[x+1][y] + myarr[x][y+1] + myarr[x+1][y+1])/4;
        cout << a << " ";
      } 
        cout << endl;
    }
    


  • merano schrieb:

    Ich würde den Speicher dynamisch besorgen; auch weil diverse Compiler "dynamische statische Arrays" nicht unterstützen.

    // Speicher besorgen
    int** myarr = new int*[spalten+(spalten%2)];
    for(int i = 0; i < spalten; ++i)
      myarr[i] = new int[zeilen+(zeilen%2)];
    

    Und genau das lässt bitteschön bleiben. Du wirst

    std::vector<std::vector<int>> myarr(spalten, std::vector<int>(zeilen, 0));
    

    nutzen. Die Syntax des restlichen Programms ändert sich dabei nicht. Dir wird sogar angezeigt, wenn du Fehler bei der Indexierung machst.


  • Mod

    Dir wird sogar angezeigt, wenn du Fehler bei der Indexierung machst.

    Da muss er schon at() verwenden.
    Edit: Zumindest garantiert ist es nicht, dass bei operator[] irgendwelche Assertions durchlaufen werden.

    Und das mit dem "zweidimensionalen vector " bitte auch lassen.

    std::vector<int> myarr(spalten * zeilen, 0);
    auto at = [&, spalten]( std::size_t x, std::size_t y ) { return myarr.at(x + y * spalten); };
    

    (Ungetestet)



  • Hallo,
    ich Danke euch vielmals fuer eure Tipps 🙂

    Diese funktionieren leider nur zum Teil.

    Das Array[10][10] wurde zwar auf ein Array[5][5] verkleinert, aber gibt nur 0 aus.

    Das Ganze eingebunden sieht so aus:

    class resize_Array{
    private:
    public:
    	void resize_Datei() {
    
            int zeilen;
            int spalten;
    
            cout << "Zeilenanzahl der ausgelesenen Datei ein: ";
            cin >> zeilen;
            cout << "Spaltenanzahl der ausgelesenen ODatei ein: ";
            cin >> spalten;
    
            int int_werte[zeilen][spalten];
            ifstream input("Test.txt");
            if(!input) {
            cout << "Die Datei wurde nicht gefunden." << endl;
            }
            // Daten Einlesen
            for(unsigned int x = 0; x != zeilen; ++x) {
                for(unsigned int y = 0; y != spalten; ++y) {
                    if(!input.eof()) {
                        input >> int_werte[x][y];
                    } else {
                        int_werte[x][y] = 0;
                     }
                }
            }
                        vector<vector<int> > myarr(spalten, vector<int>(zeilen, 0));
                        for(unsigned int y = 0; y != zeilen; y+=2) {
                        for(unsigned int x = 0; x != spalten; x+=2) {
                        int a=(myarr[x][y] + myarr[x+1][y] + myarr[x][y+1] + myarr[x+1][y+1])/4;
                        cout << a << " ";
                        }
                        cout << endl;
                        }
    
            }
    	};
    

    Diesen Code habe ich nicht verwendet, weil der Compiler fuer "at" Fehlermeldungen ausspuckt...

    std::vector<int> myarr(spalten * zeilen, 0);
    auto at = [&, spalten]( std::size_t x, std::size_t y ) { return myarr.at(x + y * spalten); };
    

    [code="cpp"]



  • Das sieht so aus, als ob dein Compiler kein C++11 kann (oder nur eingeschränkt), nutzt du vielleicht Visual Studio 2010 oder älter?

    Zum anderen: Das was merano zum Ende seines Posts geschrieben hat (die verschachtelte Schleife), die macht für sich gesehen nichts. Und du ahst sie so 1 zu 1 übernommen.

    Ein bisschen Eigeninitiative wäre angebracht...



  • Skym0sh0 schrieb:

    Das sieht so aus, als ob dein Compiler kein C++11 kann (oder nur eingeschränkt), nutzt du vielleicht Visual Studio 2010 oder älter?

    Visual Studio 2010 (oder älter) kann nicht sein wegen dem array.

    Skym0sh0 schrieb:

    Zum anderen: Das was merano zum Ende seines Posts geschrieben hat (die verschachtelte Schleife), die macht für sich gesehen nichts. Und du _hast sie so 1 zu 1 übernommen.

    Ohne Sinn und Verstand kopieren ist natürlich schädlich!

    Natürlich macht die Schleife was; sie rechnet und gibt das richtige Ergebnis aus. Wenn man aber verschiedene Quelltextteile mischt und die Kommentare nicht berücksichtigt stürzt das Programm ab, oder es kommt eben nicht das erwartete Ergebnis.

    Um sicherzustellen, das der TE sich über y(zeilen) und x(spalten) Gedanken macht
    hat mein array auch einen anderen Namen ... 😉

    Skym0sh0 schrieb:

    Ein bisschen Eigeninitiative wäre angebracht...

    Dem schliesse ich mich genau an!

    Die Idee mit dem Vector finde ich auch OK. Moderne Compiler erkennen aber auch
    Grenzen einfacher Arrays - natürlich auch Visual Studio 2010.
    Beim vector spart man gegenüber einem dynamischen array einigen Code sowie das
    Speichermanagement.



  • Das Programm selbst ist etwas fragwürdig.

    Wenn man schon modernste Sprachkonstrukte, Komfort und Sicherheit für so
    wichtig hält, sollte man auch die Anzahl der Zeilen und Spalten in einer
    separaten Datei erkennen und auf unerwartete Funde reagieren.

    Den Benutzer zu nötigen das jedes Mal einzugeben ist ungesund und lästig!



  • Boah ich Danke euch!!!

    Es klappt jetzt und ich bin super gluecklich.

    merano und Skym0sh0 ich benutze Code::Blocks GNU CC Compiler.

    merano:
    "Den Benutzer zu nötigen das jedes Mal einzugeben ist ungesund und lästig!"

    Ja das ist definitiv richtig! Da hab ich leider noch keine andere Loesung gefunden.
    Mein -weniger effiktives- Programm liest die txt-Dateien und gibt mir die Anzahl der darin gespeicherten Elemente (Zeilen und Spalten) aus .
    Ich weiß nicht, wie sich das dynamisch gestalten lässt, da sich die Zeilen und Spalten pro txt-Datei ändern. Davon habe ich nämlich knapp 2000 Dateien 😞

    Aber vielleicht lässt sich das ähnlich lösen wie das erste Problem....

    Viiiielen Dank nochmal an ALLE.



  • Anfaenger_braucht_Hilfe schrieb:

    merano schrieb:

    "Den Benutzer zu nötigen das jedes Mal einzugeben ist ungesund und lästig!"

    Ja das ist definitiv richtig! Da hab ich leider noch keine andere Loesung gefunden.
    ...
    Aber vielleicht lässt sich das ähnlich lösen wie das erste Problem....

    Selbstverständlich lässt sich auch das lösen ...

    Wie war das mir dem Appell an die Eigeninitiative ? Woran scheitert es ?

    Ich schlage eine (oder zwei) Funktionen als Ersatz für die blöde Abfrage vor.

    // cout << "Spaltenanzahl der ausgelesenen ODatei ein: ";
      // cin >> spalten;
      spalten = ZaehleSpalten(input);
    

    Und als Anregung hier auch ein (billiger) Vorschlag:

    size_t ZaehleSpalten(istream &input)
    {
      string line;
      size_t found, spalten;
    
      getline(input, line);             // zeile lesen
    
      for(spalten=0; (found=line.find(" ")) != string::npos; spalten++)
          line = line.substr(found+1, string::npos);  // restlichen Zeichen kopieren
    
      input.seekg (0, ios::beg);
    
      return spalten;
    }
    

    Hoffe das mit den Zeilen bekommst Du selber hin! 🙄


  • Mod

    @merano: Die rollenden Augen lieber bleiben lassen.

    found=line.find(" ") != string::npos
    

    Tut nicht, was es sollte. Da fehlen Klammern, die Vergleichsoperatoren binden stärker als die Zuweisungsoperatoren.
    Das fällt mir sofort auf, weil ich den Fehler schon selber einmal gemacht habe, und dafür von Pi gerügt wurde. Irgendwas mit cin.get() und einem Vergleich.

    input.seekg (0, input.beg);
    

    beg ist ein statischer Member von ios_base (und damit von ifstream), daher musst du so auf ihn zugreifen: ios::beg. (o.ä.)
    Das wiederum kam auch hier im Forum schon einmal vor, à la cin.irgendeinMember . Ich glaube, es war Nathan.

    Außerdem sollte so eine Funktion keine Referenz auf ifstream , sondern auf istream nehmen. Abstraktion wegen.

    Es ist deine Aufgabe, Code, der mehr als nur zwei Zeilen umfasst, zu testen. Sonst nützt es keinem, dass du ihn postest.



  • Arcoth schrieb:

    Tut nicht, was es sollte. Da fehlen Klammern, die Vergleichsoperatoren binden stärker als die Zuweisungsoperatoren.

    👍 So soll es sein. Verbesserungen immer willkommen.

    (Der Code war getestet und er schien das Richtige zu tun, aber ...)

    Beim optimieren hat sich dann aber wohl doch ein potentieller Operatoren Rangfolge Unfall ereignet,
    der bei der o.a. Testdatei zum gleichen Ergebnis führt und deshalb nicht aufgefallen ist.
    Ich spendiere sicherheitshalber noch einen Satz Klammern. ->Code angepasst.

    Die anderen Bedenken teile ich nicht; sind aber möglicherweise sinnvoll und ich habe sie auch eingebaut.

    Arcoth schrieb:

    Es ist deine Aufgabe, Code, der mehr als nur zwei Zeilen umfasst, zu testen. Sonst nützt es keinem, dass du ihn postest.

    Wenn ich das in zwei Zeilen geschieben hätte, wäre es nicht wirklich lesbar gewesen, oder gibt es
    eine kürzere Lösung ?



  • Danke!
    Hab eueren Post zu spät gelesen und es anders gelöst.
    Funktioniert auch 😃

    ifstream Datei;
    
            Datei.open("Test.txt",ios_base::in);
            if (!Datei){
                cout << "Datei kann nicht geoeffnet werden" << endl;
            }
            else{
                vector<vector<double> > matrix;
                while (Datei) {
                    string line;
                    getline(Datei, line);
                    istringstream iss(line);
                    vector<double> values;
                    copy(istream_iterator<double>(iss), istream_iterator<double>(), back_insert_iterator<vector<double> >(values));
                    if (values.size() > 0) matrix.push_back(values);
                }
                int zeilen;
                int spalten;
    
                zeilen = matrix.size();
                spalten = matrix[0].size();
    
                int int_werte[zeilen][spalten];
    // ...
    // damit kann man nun auch weiter arbeiten
    

    Trotzdem Danke fuer eure Ideen 🙂



  • Anfaenger_braucht_Hilfe schrieb:

    Danke!
    Hab eueren Post zu spät gelesen und es anders gelöst.
    Funktioniert auch 😃

    Stimmt, funktioniert.

    Einige Anmerkungen hätte ich dazu.

    Die Memberfunktion open ist über, da der Konstructor das bereits erledigen könnte.

    ifstream Datei("matrix.txt");
    

    Statt

    if(!Datei) { ...
    

    wäre evtl besser:

    if(!Datei.is_open()) { ...
    

    Wenn man wissen will ob die Datei geöffnet werden konnte und

    while(Datei.good()) { ...
    

    wenn man Lesefehler oder eof erkennen will.

    Das ist erheblich verständlicher und würde zuverlässlich auch mit älteren Compilern funktionieren.
    Ältere Compiler bekommen einen void* zurück, ohne das der Compiler das erkennen würde.

    Die Zeile komplett einzulesen ist wirklich besser als das Gefrickel mit der for-Schleife und hält die Matrix konsistent.

    Das Feld am Ende wird wohl garnicht mehr gebraucht.

    // int int_werte[zeilen][spalten];
    


  • Uuuh Danke merano,
    habe es gleich verbesser 🙂

    Das Feld am Ende wird gebraucht, aber wollte euch nicht mit Codes zumüllen 😉

    LG



  • Skym0sh0 schrieb:

    Du wirst

    std::vector<std::vector<int>> myarr(spalten, std::vector<int>(zeilen, 0));
    

    nutzen.

    Bin mir jetzt nicht ganz sicher, würden sich slices http://www.cplusplus.com/reference/valarray/slice/ erlauben?



  • Hi hab noch eine Frage

    Der Code ist nur ein Test und macht demnach nichts besonderes. Darum geht es mir auch gar nicht.
    Wichtig ist mir hierbei, dass die neuen Textdateien mit BILD1 BILD2 BILD3 oder
    1BILD 2BILD ... die sollen nicht alle nur BILD heißen. Ich hab da ein paar Sachen ausprobier, aber bei mir kommt BILD ILD LD raus 😞

    #include <stdio.h>
    
    int main(){
    
    int zeilen = 10;
    int spalten =10;
    int Bild [zeilen][spalten];
    int counter = 3;
    FILE *f;
    
      for (int Anzahl=0; Anzahl <= counter; Anzahl++){
    
        for (int i; i<Anzahl; i++){
            f = fopen((Anzahl+"BILD.txt"), "w"); //ich glaub hier liegt der Fehler
            if (f)
            {
    
                for(unsigned int x = 0; x < zeilen; x++) {
                    for(unsigned int y = 0; y < spalten; y++) {
                        fprintf(f,"%d ",  Bild [x][y]);
                    }
                    fprintf(f,"\n");
                }
                fclose(f);
            }
        }
      }
    }
    


  • Ja, der Fehler liegt daran.
    1. Verwende nichts aus stdio.h! Den Header gibt es gar nichtin C++. Das ist C.
    2. Mit + kannste keine Zahl an einen String hängen, es wird die Adresse vom Stringliteral genommen, Anzahl dazu addiert und dann die Stelle als String interpretiert. Verwende C++-Strings und to_string, da geht das.



  • Danke Nathan,

    hab jetzt schon viele Varianten (mit zusaetzlichen Klammern, mit + und und und) versucht, aber der macht jetzt nur noch Fehlermeldungen

    //... 
    
    string s;
    ostringstream outStream;
    outStream << Anzahl;
    s = outStream.str();
    f = fopen("BILD.txt",s, "w");
    
    //...
    


  • Nutz nicht FILE, fopen oder sonst was mit f am Anfang. Das ist C!

    Mit + kannste keine Zahl an einen String hängen [...] Verwende C++-Strings [...], da geht das.


Anmelden zum Antworten