mit dem stringgrid zeichen sortieren



  • hi,

    ich schaffe es einfach nich in einem stringgrid zahlen und zeichen zu sortieren,

    dank dem FAQ kann ich zahlen sortieren,
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-39156.html

    aber sobald ich buchsteben eingebe bekomme ich die fehlermeldung das diese zeichen kein integer ist,

    wenn ich aber den code (qsort) anschaue sehe ich das dort strings verglichen werden, oder stimmt das nicht?

    könnt mir hinweise geben, dann versuche ich auf die lösung zu kommen,
    für jede kommentare offen,

    mfg

    HubiS

    void __fastcall TForm1::QuickSortColumn(TStringGrid *grid, int Column, int links, int rechts, bool Desc)
        {
        Column = 0;
        // rechte und linke grenze festlegen
        int i = links;
        int j = rechts;
        // den mittelwert bestimmen (sortierung aufteilen)
        int m = StrToInt(grid->Cells[Column][(int) ((links + rechts) / 2)]);
        do
        {
            // sortier-reihenfolge festlegen
            while (Desc ? (StrToInt(grid->Cells[Column][i]) < m) : (StrToInt(grid->Cells[Column][i]) > m)) i++;
            while (Desc ? (m < StrToInt(grid->Cells[Column][j])) : (m > StrToInt(grid->Cells[Column][j]))) j--;
            if (i <= j)
            {
                // Zeilen tauschen
                AnsiString tmp;
                tmp = grid->Rows[i]->CommaText;
                grid->Rows[i]->CommaText = grid->Rows[j]->CommaText;
                grid->Rows[j]->CommaText = tmp;
                i++;
                j--;
            }
        }
        while (i < j);
        // rekursiver aufruf
        if (links < j) QuickSortColumn(grid, Column, links, j, Desc);
        if (i < rechts) QuickSortColumn(grid, Column, i, rechts, Desc);
        // damit ich nicht die CheckBox benutze, geht bestimmt einfacher,
        if (CheckBox1 -> Checked == 0)
              CheckBox1 -> Checked = 1;
        else {CheckBox1 -> Checked = 0;}
    }
    

    aufruf mit ->

    QuickSortColumn(StringGrid1, StringGrid1 -> Row, StringGrid1->FixedRows, StringGrid1->RowCount - 1, CheckBox1 -> Checked);
    


  • Hallo

    aber sobald ich buchsteben eingebe bekomme ich die fehlermeldung das diese zeichen kein integer ist,

    Und was wundert dich daran?

    wenn ich aber den code (qsort) anschaue sehe ich das dort strings verglichen werden, oder stimmt das nicht?

    Wenn Strings verglichen werden, heißt das doch nicht, das diese in Zahlen umgewandelt werden müßen. Sondern es werden (ums kurz zumachen) die einzelnen Chars nacheinander von links nach rechts verglichen, und diese sind ja integer.

    Du kannst/must also Strings genauso wie Zahlen vergleichen.

    bis bald
    akari



  • wenn ich zB "a" mit "1" (eins) vergleiche bekomme ich in der ausgabe das a größer als 1 ist,

    nur mal zum verständnis:

    string -> zeichen von null bis Z, auch sonder zeichen,
    char -> nur zeichen ohne buchstaben,
    int -> nur Zahlen

    mein quellcode:

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
    if (Edit1 -> Text < Edit2 -> Text)
        Panel1 -> Caption = Edit1 -> Text + " < " + Edit2 -> Text;
    if (Edit1 -> Text > Edit2 -> Text)
        Panel1 -> Caption = Edit1 -> Text + " > " + Edit2 -> Text;
    }
    

    kann ich ein stringgrid mit ein edit feld vergleichen, meine jetzt die "bauart",

    wenn ich das ändere

    StrToInt(grid->Cells[Column][i]) < m
    

    in

    grid->Cells[Column][i] < m
    

    tauchen probleme auf,

    ist mein ansatz richtig ..??



  • naja du kannst den quicksort entsprechend für dich anpassen und so erweitern, dass du die entsprechenden spalten nach ihrem datentyp sortierst. um es ein weniger portabler für andere bcb-projekte zu machen, kannste auch deinem stringgrid auch über die Object-Eigenschaft nen Wert zuweisen, den du hier beim sortieren ausliest und der die art der daten in der spalte festlegt. dann musst du nicht für jedes stringgrid nen eigenen sortieralgo schreiben.

    // m muss natürlich dann auch je nach spalte und sortiertyp unterschiedlich sein!
    switch (Column)
    {  
      // Spalte 1 (Strings sortieren)
      // Spalte 3
      case 0 : 
      case 2 :
      {
        while (Desc ? AnsiCompareStr(grid->Cells[Column][i], m) < 0 : AnsiCompareStr(grid->Cells[Column][i], m) > 0) i++; 
        while (Desc ? AnsiCompareStr(m, grid->Cells[Column][j]) < 0 : AnsiCompareStr(m, grid->Cells[Column][j]) > 0) j--; 
        break;
      }
    
      // Spalte 2 (Zahlen sortieren)
      case 1 :
      {
        while (Desc ? (StrToInt(grid->Cells[Column][i]) < m) : (StrToInt(grid->Cells[Column][i]) > m)) i++; 
        while (Desc ? (m < StrToInt(grid->Cells[Column][j])) : (m > StrToInt(grid->Cells[Column][j]))) j--; 
        break;
      }
    }
    

    das sollte zwar funktionieren, ist allerdings nicht wirklich schön.

    Wenn es wirklich effizient sein soll (sehr viele Datensätze). Dann schreibst du dir besser einen eigenen Indexsortierer und sortierst jeweils die entsprechende Spalte und passt lediglich die Indizes in einer separaten Liste an. Das ist schnell, denn du sparst die ganzen Zuweisungen und Kopierereien, da du lediglich die Indizes (integer) vertauschst. danach schreibst du die daten gemäß der umsortierten Indexliste wieder in deine Tabelle.



  • also soweit dankr für die infos,

    nur stimmt da was net,
    ich habe vergessen zu erwähnen das bei mir
    Column = 0 ist,

    weil ich nur die erste spalte sortieren will,

    zB:
    |_____Film______|__Size__|
    |.Matrix........|.700.MB.|
    |.23............|.600.MB.|
    |.30.über.nacht.|.650.MB.|

    so will ich meine tabelle benutzen,
    wenn jetzt auf film gedrückt wird werden die filme sortiert,

    deshalb ja auch zahlen und buchstaben,

    der rest ist mir erstmal egal,

    hier der nicht funktionsfähige modifizierte code

    void __fastcall TForm1::QuickSortColumn(TStringGrid *grid, int Column, int links, int rechts, bool Desc)
        {
        //Column = 0;
        // rechte und linke grenze festlegen
        int i = links;
        int j = rechts;
        // den mittelwert bestimmen (sortierung aufteilen)
        int m = StrToInt(grid->Cells[Column][(int) ((links + rechts) / 2)]);
        do
        {
            // sortier-reihenfolge festlegen
        //    while (Desc ? ((grid->Cells[Column][i]) < m) : (StrToInt(grid->Cells[Column][i]) > m)) i++;
        //    while (Desc ? (m < StrToInt(grid->Cells[Column][j])) : (m > StrToInt(grid->Cells[Column][j]))) j--;
    //     while (Desc ? AnsiCompareStr(grid->Cells[Column][i], m) < 0 : AnsiCompareStr(grid->Cells[Column][i], m) > 0) i++;
     //    while (Desc ? AnsiCompareStr(m, grid->Cells[Column][j]) < 0 : AnsiCompareStr(m, grid->Cells[Column][j]) > 0) j--;
    // m muss natürlich dann auch je nach spalte und sortiertyp unterschiedlich sein!
    switch (Column)
    {
      // Spalte 1 (Strings sortieren)
      // Spalte 3
     // case 0 :
      case 0 :
      {
        while (Desc ? AnsiCompareStr(grid->Cells[Column][i], m) < 0 : AnsiCompareStr(grid->Cells[Column][i], m) > 0) i++;
        while (Desc ? AnsiCompareStr(m, grid->Cells[Column][j]) < 0 : AnsiCompareStr(m, grid->Cells[Column][j]) > 0) j--;
        break;
      }
    
      // Spalte 2 (Zahlen sortieren)
      case 1 :
      {
        while (Desc ? (StrToInt(grid->Cells[Column][i]) < m) : (StrToInt(grid->Cells[Column][i]) > m)) i++;
        while (Desc ? (m < StrToInt(grid->Cells[Column][j])) : (m > StrToInt(grid->Cells[Column][j]))) j--;
        break;
      }
    }
            if (i <= j)
            {
                // Zeilen tauschen
                AnsiString tmp;
                tmp = grid->Rows[i]->CommaText;
                grid->Rows[i]->CommaText = grid->Rows[j]->CommaText;
                grid->Rows[j]->CommaText = tmp;
                i++;
                j--;
            }
        }
        while (i < j);
        // rekursiver aufruf
        if (links < j) QuickSortColumn(grid, Column, links, j, Desc);
        if (i < rechts) QuickSortColumn(grid, Column, i, rechts, Desc);
        // damit ich nicht die CheckBox benute, geht bestimmt einfacher,
        if (CheckBox1 -> Checked == 0)
              CheckBox1 -> Checked = 1;
        else {CheckBox1 -> Checked = 0;}
    }
    


  • na wenn du nur eine spalte sortieren willst, kannste das geswitche auch weglassen, allerdings muss m (wie schon geschrieben) auch vom Typ AnsiString sein! Also einfach die Konvertierung weglassen.



  • @sunday
    ich danke dir für die hilfe,

    nur habe ich ein problem wenn alles sortiert wird,
    weren die zahlen nicht nach der größe 1,3,4,5,... etc

    sondern wie zeichen behandelt,
    a, aa, aaa, b, bb, bbb,
    hier die zahlen -> 1, 11, 111, 2, 22, 222, ... etc

    und bei kombinationen von zeichen und zahlen das gleiche problem auftaucht,

    ein bsp.1.: test1, test11, test111, test2, test22, test222, ... etc

    bsp.2.: test11, test11, tfst1, tfst2,

    hilfe bitte,

    mfg

    HubiS

    void __fastcall TForm1::QuickSortColumn(TStringGrid *grid, int Column, int links, int rechts, bool Desc)
        {
        Column = 0;
        // rechte und linke grenze festlegen
        int i = links;
        int j = rechts;
        // den mittelwert bestimmen (sortierung aufteilen)
        //int m = StrToInt(grid->Cells[Column][(int) ((links + rechts) / 2)]);
        AnsiString m = (grid->Cells[Column][((links + rechts) / 2)]);
        do
        {
            // sortier-reihenfolge festlegen
        //    while (Desc ? ((grid->Cells[Column][i]) < m) : (StrToInt(grid->Cells[Column][i]) > m)) i++;
        //    while (Desc ? (m < StrToInt(grid->Cells[Column][j])) : (m > StrToInt(grid->Cells[Column][j]))) j--;
    //        while (Desc ? (StrToInt(grid->Cells[Column][i]) < m) : (StrToInt(grid->Cells[Column][i]) > m)) i++;
    //        while (Desc ? (m < StrToInt(grid->Cells[Column][j])) : (m > StrToInt(grid->Cells[Column][j]))) j--;
         while (Desc ? AnsiCompareStr(grid->Cells[Column][i], m) < 0 : AnsiCompareStr(grid->Cells[Column][i], m) > 0) i++;
         while (Desc ? AnsiCompareStr(m, grid->Cells[Column][j]) < 0 : AnsiCompareStr(m, grid->Cells[Column][j]) > 0) j--;
     if (i <= j)
            {
                // Zeilen tauschen
                AnsiString tmp;
                tmp = grid->Rows[i]->CommaText;
                grid->Rows[i]->CommaText = grid->Rows[j]->CommaText;
                grid->Rows[j]->CommaText = tmp;
                i++;
                j--;
            }
        }
        while (i < j);
        // rekursiver aufruf
        if (links < j) QuickSortColumn(grid, Column, links, j, Desc);
        if (i < rechts) QuickSortColumn(grid, Column, i, rechts, Desc);
        // damit ich nicht die CheckBox benute, geht bestimmt einfacher,
        if (CheckBox1 -> Checked == 0)
              CheckBox1 -> Checked = 1;
        else {CheckBox1 -> Checked = 0;}
    }
    


  • Huberts schrieb:

    ....
    nur habe ich ein problem wenn alles sortiert wird,
    weren die zahlen nicht nach der größe 1,3,4,5,... etc

    sondern wie zeichen behandelt,
    a, aa, aaa, b, bb, bbb,
    hier die zahlen -> 1, 11, 111, 2, 22, 222, ... etc

    und bei kombinationen von zeichen und zahlen das gleiche problem auftaucht,

    ein bsp.1.: test1, test11, test111, test2, test22, test222, ... etc

    bsp.2.: test11, test11, tfst1, tfst2,
    ...

    Das Ergebniss ist genau so, wie man es bei lexikalischer Sortierung erwartet.
    Wenn du Spalten hast, in denen ausschließlich Zahlen stehen, könntest du diese numerisch sortieren, aber bei gemischten Ausdrücken geht das nicht.

    void __fastcall TForm1::QuickSortColumn(TStringGrid *grid, int Column, int links, int rechts, bool Desc, bool AlphaSort)
    {
       if (AlphaSort)
          ; //deine neue alphanumerische Sortierfunktion
       else
          ; //die alte rein numerische Sortierung
    }
    

    Machmal hilft bei lexikalischer Sortierung folgender Workaround: Einfach die Zahl mit Nullen auffüllen, z.B. 01.Lied_1, 02.Lied_2, 12.Lied_12. Aber bei den von dir genannten Beispielen geht das nicht.



  • Am besten ist es wohl, wenn du dir hier deine eigene Vergleichsfunktion schreibst.


Anmelden zum Antworten