Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Compare strings special order [natural sorting]
rollerfreak2
myCSharp.de - Member

Avatar #avatar-3271.jpg


Dabei seit:
Beiträge: 928

Themenstarter:

Compare strings special order [natural sorting]

beantworten | zitieren | melden

Hallo zusammen,

eine kleine Frage bezüglich string compare. Ein normaler string compare "sortiert" folgende 3 strings "item_2", "item_1", "item_11".

Das Ergebnis lautet wenig überaschend: "item_1", "item_11", "item_2".
Ich möchte aber folgendes "item_1", "item_2", "item_11". Dabei soll es aber auch egal sein, was hinter der Zahl steht. Daher "item_1z" kommt vor "item_11".

Gibt es da irgendeine Compare logik die das schon beherscht, oder muss ich selber via Regex anfangen was zu implementieren.

Mein Plan wäre foldender:

1) Mit regex aus beiden string's den kompletten Anfangsteil + Digit's extrahieren.
2) Ist einer von beiden matches negativ, den normalen string compare anwerfen.
3) Sind beide matches positiv, dann wird zu erst geprüft ob die beiden "anfangs" string gleich sind, wenn nicht wieder den normalen string compare anwerfen
4) Bin ich bis hier her gekommen einfach die beiden Zahlen miteinander vergleichen, sind diese zufällig gleich, dann einfach den normalen string compare anwerfen

Hat jemand einen besseren Vorschlag?
Again what learned...
private Nachricht | Beiträge des Benutzers
davidG
myCSharp.de - Member



Dabei seit:
Beiträge: 67

beantworten | zitieren | melden

Moin,

ich wüsste grad keinen feritgen Comparer, der sowas schon kann. (Lasse mich aber auch gerne belehren.

Wie liegen dir die Strings vor? Als List oder Array oder... ?
Trifft auf jeden String das Must item_x (x ist eine Zahl) zu?

Willst du nur nach der Zahl sortieren oder spielt der String, der vor der Zahl steht, auch eine Rolle?

Grüße
DavidG
„Ich erfand den Begriff «objekt-orientiert», und ich kann sagen, dass ich dabei nicht C++ im Sinn hatte.“ Alan Kay
private Nachricht | Beiträge des Benutzers
rollerfreak2
myCSharp.de - Member

Avatar #avatar-3271.jpg


Dabei seit:
Beiträge: 928

Themenstarter:

beantworten | zitieren | melden

Die strings liegen als string's vor, daher ein Comparer Implementieren und dort dann das CompareTo implementieren.

Fertige Sortierungen:

"affe_1", "egon_2"

"af2fe_1", "af2fe_2", "af2fe_11"

"af1fe_2", "af2fe_1", "af2fe_11"

....
Zitat
Willst du nur nach der Zahl sortieren oder spielt der String, der vor der Zahl steht, auch eine Rolle?

Siehe Muster oben.
Zitat
Trifft auf jeden String das Must item_x (x ist eine Zahl) zu?

Nein, ich würde es mal so matchen: "^[A-Za-z0-9_]*(\d)+"
Zitat
Wie liegen dir die Strings vor? Als List oder Array oder... ?

Also generische list, aber was hat das mit der Frage zu tun?


list.Sort(new MyComparer());
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von rollerfreak2 am .
Again what learned...
private Nachricht | Beiträge des Benutzers
davidG
myCSharp.de - Member



Dabei seit:
Beiträge: 67

beantworten | zitieren | melden

Wie wäre es, wenn du dir eine Klasse für die einzelne Items baust. In der Klasse hast du ein Feld für den Zahlenwert und ein Feld für den String Wert. Desweiteren implementiert die Klasse das Interface IComparable<T>. Du musst die Methode CompareTo(Item item) ausimplementieren. Dort überprüfen, ob der die Stringwerte gleich sind. Ist dies der Fall, die Zahlenwerte miteinander verlgeichen.

Anschließend kannst du über List.Sort() die Liste sortieren lassen.

z.b.

    
public class Item : IComparable<Item>
    {
        private int _digit;

        private string _str;

        public int Digit
        {
            get { return _digit; }
            set { _digit = value; }
        }

        public string Str
        {
            get { return _str; }
            set { _str = value; }
        }

        public int CompareTo(Item other)
        {
            if(_str.CompareTo(other.Str)== 0)
            {
                return _digit.CompareTo(other.Digit);
            }

            return _str.CompareTo(other.Str);
        }
    }
Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von davidG am .
„Ich erfand den Begriff «objekt-orientiert», und ich kann sagen, dass ich dabei nicht C++ im Sinn hatte.“ Alan Kay
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4183

beantworten | zitieren | melden

Auf CodeProjekt gibt es schon einen "Numeric String Comparer": http://www.codeproject.com/KB/recipes/csnsort.aspx

Und unter http://dotnetperls.com/alphanumeric-sorting noch eine ähnliche Klasse namens AlphanumComparatorFast.
private Nachricht | Beiträge des Benutzers
rollerfreak2
myCSharp.de - Member

Avatar #avatar-3271.jpg


Dabei seit:
Beiträge: 928

Themenstarter:

beantworten | zitieren | melden

Zitat
In der Klasse hast du ein Feld für den Zahlenwert und ein Feld für den String Wert.

Wie gesagt der Wert liegt als STRING vor, deine Lösung funzt also so nicht. Ich müsste erst die digits nach einem speziellen pattern extrahieren, wie ich oben aufgezeigt habe. Das ist ja eigentlich die Problem Stellung, deine aufgezeigte Lösung setzt die eigentliche Lösung ja schon voraus.

Die beiden Links von Th69 sehen sehr vielversprechend aus. Die schau ich mir mal an. Danke
Again what learned...
private Nachricht | Beiträge des Benutzers
iced-t89
myCSharp.de - Member



Dabei seit:
Beiträge: 293

beantworten | zitieren | melden

Versuchs mal mit "natural sorting"
private Nachricht | Beiträge des Benutzers
davidG
myCSharp.de - Member



Dabei seit:
Beiträge: 67

beantworten | zitieren | melden

Naja, mir war nicht genau so klar, wo dein Problem liegt und nachdem du schon ein Regex-Pattern gepostet hattest, dachte ich, dass du diese Problem schon gelöst hättest.

Du kannst ja den String-Wert in einen Int Wert casten.

Für Reguläre-Ausdrücke gibt es ein klasse Tool (Regex-Lab) von herbivore mit dem man Patterns erstellen / testen kann: Regex-Lab

Das Pattern, mit dem du zum einen den String-Wert (z.B. Affe) und anschließend den numerischen Wert (1) bekommst, lautet: (\w+)_(\d+)

Bei "affe_1" bekommst du somit für den ersten Wert affe und für den zweiten wert die 1.

Ein Regex-Tutorial gibt es hier: Regex Tutorial

So könntest du auch Match-Ergebnisse zu greifen:


Regex myRegex = new Regex("(\\w+)_(\\d+)");
Match myMatch = myRegex.Match(content);

while (myMatch.Success)
{
     string stringValue = myMatch.Groups[1].Value;
     int digitValue =  int.Parse( myMatch.Groups[2].Value)

     myMatch = myMatch.NextMatch();
}

Und so hättest du die einzelnen Werte
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von davidG am .
„Ich erfand den Begriff «objekt-orientiert», und ich kann sagen, dass ich dabei nicht C++ im Sinn hatte.“ Alan Kay
private Nachricht | Beiträge des Benutzers
davidG
myCSharp.de - Member



Dabei seit:
Beiträge: 67

beantworten | zitieren | melden

Oder wenn du ausschließen kannst, dass nach dem _ was anderes als zahlen kommst, könntest du den string auch mit string.Split("_") teilen
„Ich erfand den Begriff «objekt-orientiert», und ich kann sagen, dass ich dabei nicht C++ im Sinn hatte.“ Alan Kay
private Nachricht | Beiträge des Benutzers
rollerfreak2
myCSharp.de - Member

Avatar #avatar-3271.jpg


Dabei seit:
Beiträge: 928

Themenstarter:

beantworten | zitieren | melden

Zitat
Für Reguläre-Ausdrücke gibt es ein klasse Tool (Regex-Lab) von herbivore mit dem man Patterns erstellen / testen kann: Regex-Lab

Das weis ich schon danach habe ich ja gar nicht gefragt.
Zitat
Ein Regex-Tutorial gibt es hier: Regex Tutorial

Ich weis mit Regex um zu gehen, es ging nur darum nicht etwas zu implementieren was es bereits gibt. Und dazu hat Th69 die passende Antwort gehabt.
Again what learned...
private Nachricht | Beiträge des Benutzers
davidG
myCSharp.de - Member



Dabei seit:
Beiträge: 67

beantworten | zitieren | melden

wohl ein missverständnis
„Ich erfand den Begriff «objekt-orientiert», und ich kann sagen, dass ich dabei nicht C++ im Sinn hatte.“ Alan Kay
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo rollerfreak2,

siehe auch Natürliche Sortierung implementieren ("img2.jpg" vor "img10.jpg") (und insbesondere dieser Beitrag in Natürliche Sortierung implementieren ("img2.jpg" vor "img10.jpg")).

herbivore
private Nachricht | Beiträge des Benutzers
rollerfreak2
myCSharp.de - Member

Avatar #avatar-3271.jpg


Dabei seit:
Beiträge: 928

Themenstarter:

beantworten | zitieren | melden

Hallo herbivore,

danke noch mal für den Link. Der 2te Link von Th69 sah auch viel verprechend aus und funktioniert soweit ohne Fehler. Er ist auch sehr schnell, ob nun aber die Implementierung deines Links oder des externen schneller ist, habe ich noch nicht ausprobiert.
Again what learned...
private Nachricht | Beiträge des Benutzers
davidG
myCSharp.de - Member



Dabei seit:
Beiträge: 67

beantworten | zitieren | melden

natural sorting klingt echt interessant und jetzt habe ich auch gecheckt, was du wolltest.
„Ich erfand den Begriff «objekt-orientiert», und ich kann sagen, dass ich dabei nicht C++ im Sinn hatte.“ Alan Kay
private Nachricht | Beiträge des Benutzers