| |
VB.NET - FortgeschritteneRe: IComparer sortiert nicht richtig | | | Autor: Bitscheucher | Datum: 11.08.11 12:35 |
| Hallo Dave,
danke für den Hinweis - werde ich gleich umsetzen.
Viele Grüße
Bitscheucher | |
IComparer sortiert nicht richtig | | | Autor: Bitscheucher | Datum: 11.08.11 10:15 |
| Hallo Forum,
ich stehe vor einem Problem, das ich leider trotz googeln, lesen und nachdenken nicht lösen kann:
In meinem Programm zum Taggen und Verwalten von MP3-Dateien lasse ich mir den Inhalt von Verzeichnissen in einer explorerähnlichen Form anzeigen (linker Teil: TreeView zum Anzeigen des Verzeichnisbaumes; rechter Teil: ListView zum Anzeigen der MP3-Dateien des ausgewählten Verzeichnisses) - klappt soweit.
Um nun Verzeichnisnamen mit Sonderzeichen oder Zahlen (z.B. Rock1, Rock2, Rock3, ... Rock15) im Namen in die richtige (aufsteigende) Reihenfolge zu bekommen habe ich in einer Klasse folgenden Code geschrieben:
' Nodes zum TreeView
Public Sub FillTreeNode(ByVal DrvNode As TreeNode)
Try
Dim DI As New DirectoryInfo(DrvNode.FullPath)
Dim DirInfos() As DirectoryInfo = DI.GetDirectories
' Sortierung aufrufen
Array.Sort(DirInfos, New DirNameComparer)
...
End Sub
' Sortierung
Public Class DirNameComparer
Implements IComparer(Of DirectoryInfo)
Public Function Compare(ByVal x As DirectoryInfo, ByVal y As DirectoryInfo) _
As Integer Implements IComparer(Of DirectoryInfo).Compare
Dim xval As Integer
Dim xPos As Integer
Dim xNumber As String
Dim yval As Integer
Dim yPos As Integer
Dim yNumber As String
Dim Z As Integer
Dim CI As CompareInfo = CompareInfo.GetCompareInfo("de-DE")
' Zahlen aus den zu vergleichenden Strings auslesen:
' Erster String: Position der ersten Ziffer feststellen
Dim xPos As Integer = _
x.Name.IndexOfAny(New Char() {"0"c, "1"c, "2"c, "3"c, "4"c, "5"c, "6"c, _
"7"c, "8"c, "9"c})
' Zweiter String: Position der ersten Ziffer feststellen
Dim yPos As Integer = _
y.Name.IndexOfAny(New Char() {"0"c, "1"c, "2"c, "3"c, "4"c, "5"c, "6"c, _
"7"c, "8"c, "9"c})
' Ziffern müssen an derselben Position innnerhalb der zu vergleichenden
' Strings stehen
If xPos > -1 AndAlso yPos > -1 AndAlso xPos = yPos Then
' Die zu vergleichenden Strings müssen bis zu den isolierten
' Ziffern gleich sein; ('Hardrock' soll nicht mit 'Hartrock'
' verglichen werden)
If x.Name.StartsWith(y.Name.Substring(0, yPos)) Then
' Zahlen können 1-, 2- usw.-stellig sein: Stellenanzahl
' feststellen
' Im erster String
For Z = xPos To x.Name.Length - 1
If Not IsNumeric(x.Name.Substring(Z, 1)) Then Exit For
Next
' Zahl aus erstem String isolieren (Z - xPos = Stellenanzahl)
xNumber = x.Name.Substring(xPos1, Z - xPos)
' Und im zweiten String
For Z = yPos To y.Name.Length - 1
If Not IsNumeric(y.Name.Substring(Z, 1)) Then Exit For
Next
yNumber = y.Name.Substring(yPos1, Z - yPos)
' Isolierte Zahlen mit TryParse als Integerwerte vergleichen
If Integer.TryParse(xNumber, xval) AndAlso Integer.TryParse( _
yNumber, yval) Then
Return xval.CompareTo(yval)
End If
Else
' Strings bis zu den isolierten Ziffern unterschiedlich -
' Stringvergleich durchführen
Return CI.Compare(x.Name, y.Name)
End If
Else
' Ziffern an unterschiedlichen Positionen oder keine Zahlen in den
' zu vergleichenden Strings oder einer mit Zahl, einer ohne -
' Stringvergleich durchführen (verhindert, dass Céline Dion (wg.
' des Akkuts) an das Ende aller Verzeichnisse, die mit C beginnen,
' rutscht)
Return CI.Compare(x.Name, y.Name)
End If
End Function Das funktioniert auch sehr gut, die Verzeichnisnamen sind aufsteigend, aber: Wenn manche Sampler aus 2 oder mehr CDs bestehen (also Rock1 - CD1, Rock1 - CD2, Rock2 - CD1, Rock2 - CD2 oder gar: Rock6 - CD1, Rock6 - CD2, Rock6 - CD3) dann ist die Sortierung der CDs zufällig. Die Verzeichnisnamen werden dann etwa so angezeigt:
Rock1 - CD2, Rock1 - CD1, Rock2 - CD1, Rock2 - CD2, Rock6 - CD2, Rock6 - CD3, Rock6 - CD1.
Wer kann mir hier weiterhelfen? Bin für Anregungen und Tipps sehr dankbar.
Viele Grüße
Bitscheucher | |
Re: IComparer sortiert nicht richtig - Lösung | | | Autor: Bitscheucher | Datum: 11.08.11 14:36 |
| Hallo,
ich habe den Hinweis von Dave umgesetzt und nachdem die ersten Zahlen verglichen wurden, im verbleibenden "Rest" nach weiteren Zahlen gesucht - es funktioniert.
Für alle, die es interessiert, hier die Lösung:
Public Sub FillTreeNode(ByVal DrvNode As TreeNode)
Try
Dim DI As New DirectoryInfo(DrvNode.FullPath)
Dim DirInfos() As DirectoryInfo = DI.GetDirectories
' Sortierung aufrufen
Array.Sort(DirInfos, New DirNameComparer)
.....
Catch
End Try
End Sub
' Sortierung
Public Function Compare(ByVal x As DirectoryInfo, ByVal y As DirectoryInfo) _
As Integer Implements IComparer(Of DirectoryInfo).Compare
Dim Z As Integer
Dim xNumber1 As String
Dim xNumber2 As String
Dim yNumber1 As String
Dim yNumber2 As String
Dim xval As Integer
Dim yval As Integer
Dim CI As CompareInfo = CompareInfo.GetCompareInfo("de-DE")
' Zahlen aus den zu vergleichenden Strings auslesen:
Dim xPos1 As Integer = _
x.Name.IndexOfAny(New Char() {"0"c, "1"c, "2"c, "3"c, "4"c, "5"c, "6"c, _
"7"c, "8"c, "9"c})
' Zweiter String: Position der ersten Ziffer feststellen
Dim yPos1 As Integer = _
y.Name.IndexOfAny(New Char() {"0"c, "1"c, "2"c, "3"c, "4"c, "5"c, "6"c, _
"7"c, "8"c, "9"c})
' Ziffern müssen an derselben Position innnerhalb der zu vergleichenden
' Strings stehen
If xPos1 > -1 AndAlso yPos1 > -1 AndAlso xPos1 = yPos1 Then
' Die zu vergleichenden Strings müssen bis zu den gefundenen
' Ziffern gleich sein ('Hardrock' soll nicht mit 'Hartrock'
' verglichen werden)
If x.Name.ToLower.StartsWith(y.Name.ToLower.Substring(0, yPos1)) _
Then
' Zahlen können 1-, 2- usw.-stellig sein: Stellenanzahl
' feststellen
' Im ersten String
For Z = xPos1 To x.Name.Length - 1
If Not IsNumeric(x.Name.Substring(Z, 1)) Then Exit For
Next
' Zahl aus erstem String isolieren (Z - xPos1 = Stellenanzahl)
xNumber1 = x.Name.Substring(xPos1, Z - xPos1)
' Und im zweiten String
For Z = yPos1 To y.Name.Length - 1
If Not IsNumeric(y.Name.Substring(Z, 1)) Then Exit For
Next
yNumber1 = y.Name.Substring(yPos1, Z - yPos1)
' Isolierte Zahlen mit TryParse als Integerwerte vergleichen
If Integer.TryParse(xNumber1, xval) AndAlso Integer.TryParse( _
yNumber1, yval) Then
' Isolierte Zahlen identisch - jetzt nach den CD-Nummern
' suchen
If xval = yval Then
' Zu vergleichende Strings hinter erster Zahl
Dim xSubStr As String = x.Name.Substring(xPos1 + _
xNumber1.Length)
Dim ySubStr As String = y.Name.Substring(yPos1 + _
yNumber1.Length)
Dim xPos2 As Integer = _
xSubStr.IndexOfAny(New Char() {"0"c, "1"c, "2"c, "3"c, _
"4"c, "5"c, "6"c, "7"c, "8"c, "9"c})
Dim yPos2 As Integer = _
ySubStr.IndexOfAny(New Char() {"0"c, "1"c, "2"c, "3"c, _
"4"c, "5"c, "6"c, "7"c, "8"c, "9"c})
' Wenn weitere Zahlen in den SubStr vorhanden
If xPos2 > -1 AndAlso yPos2 > -1 AndAlso xPos2 = _
yPos2 Then
For Z = xPos2 To xSubStr.Length - 1
If Not IsNumeric(xSubStr.Substring(Z, 1)) Then _
Exit For
Next
xNumber2 = xSubStr.Substring(xPos2, Z - xPos2)
For Z = yPos2 To ySubStr.Length - 1
If Not IsNumeric(ySubStr.Substring(Z, 1)) Then _
Exit For
Next
yNumber2 = ySubStr.Substring(yPos2, Z - yPos2)
If Integer.TryParse(xNumber2, xval) AndAlso _
Integer.TryParse(yNumber2, yval) Then
Return (xval.CompareTo(yval))
Else
Return (CI.Compare(x.Name, y.Name))
End If
End If
Else
Return xval.CompareTo(yval)
End If
Else
Return xval.CompareTo(yval)
End If
Else
Return CI.Compare(x.Name, y.Name)
End If
Else
Return CI.Compare(x.Name, y.Name)
End If
End Function Viele Grüße
Bitscheucher | |
Re: IComparer sortiert nicht richtig - Lösung | | | Autor: FZelle (Moderator) | Datum: 11.08.11 14:51 |
| Und warum machst du es so umständlich, statt den Rest ggf durch einen weiteren Aufruf der Funktion erledigen zu lassen? | |
Re: IComparer sortiert nicht richtig - Lösung | | | Autor: Bitscheucher | Datum: 11.08.11 16:28 |
| @FZelle:
Ich muss gestehen, dass ich Dir leider nicht ganz folgen kann. Aus der Sub 'FillTreeNode' übergebe ich ein Array aus DirectoryInfos an die Function 'Compare'. Innerhalb der Function behandle ich die Namen der DirectoryInfos als Strings bzw. Teile davon als Integerwerte.
Ich sehe jetzt keine Möglichkeit die Function nochmals aufzurufen - oder bin ich auf dem Holzweg? | |
Re: IComparer sortiert nicht richtig - Lösung | | | Autor: FZelle (Moderator) | Datum: 12.08.11 10:05 |
| Ja, bist du.
Du sollst statt den ganzen Code zu verdoppeln einfach einen Stringcomparer machen, und den dann von deinem DirectoryInfo Comparer aufrufen.
Hier dann den ersten String separieren, und bei Gleichheit die selbe Routine nochmal mit dem Reststring aufrufen.
Solange bis du ein Ergebnis hast, oder die zu vergleichenden stings dann leer sind, dann sind sie gleich. | |
Re: IComparer sortiert nicht richtig - Lösung | | | Autor: Bitscheucher | Datum: 12.08.11 15:23 |
| Hallo FZelle,
hat funktioniert - ich habe einen String-Comparer aufgebaut - gleich dem DirectoryInfo-Comparer - und nur den sich wiederholenden Codeteil umgebaut, so dass es jetzt so aussieht:....
If xval = yval Then
' Zu vergleichende Strings hinter erster Zahl
Dim xSubStr As String = x.Substring(xPos1 + xnumber1.Length)
Dim ySubStr As String = y.Substring(yPos1 + yNumber1.Length)
Compare(xSubstr, ySubstr)
.... Vielen Dank für den Tip.
Bitscheucher | |
| Sie sind nicht angemeldet! Um auf diesen Beitrag zu antworten oder neue Beiträge schreiben zu können, müssen Sie sich zunächst anmelden.
Einloggen | Neu registrieren |
|
|
sevISDN 1.0
Überwachung aller eingehender Anrufe!
Die DLL erkennt alle über die CAPI-Schnittstelle eingehenden Anrufe und teilt Ihnen sogar mit, aus welchem Ortsbereich der Anruf stammt. Weitere Highlights: Online-Rufident, Erkennung der Anrufbehandlung u.v.m. Weitere InfosTipp des Monats sevAniGif (VB/VBA)
Anzeigen von animierten GIF-Dateien
Ab sofort lassen sich auch unter VB6 und VBA (Access ab Version 2000) animierte GIF-Grafiken anzeigen und abspielen, die entweder lokal auf dem System oder auf einem Webserver gespeichert sind. Weitere Infos
|