Requirement: Double letter revs - a to z - then repeat with aa, ab, ac...etc. with rev aa before z. Length before alpha, then descending by alpha.
So, for custom sorting of the revision version, the
IComparer<t> Interface
[
^] is best suited for this task. Here is a comparer that will sort based on length, then alpha revision letter:
Class RevisionComparer
Implements IComparer(Of String)
Private Function IComparer_Compare(x As String, y As String) As Integer _
Implements IComparer(Of String).Compare
If x = y Then Return 0
If x.Length > y.Length Then Return 1
If x.Length < y.Length Then Return -1
If x.Length = y.Length Then
For i As Integer = 0 To x.Length - 1
If x(i) > y(i) Then Return 1
If x(i) < y(i) Then Return -1
Next
End If
Return 0
End Function
End Class
Before we can do anything, we need to create and test the
RevisionComparer
class:
Module Module1
Sub Main()
Dim testRevisions = New List(Of String)() From {
"c",
"aa",
"az",
"ba",
"bz",
"aaa",
"bca",
"cba",
"aza",
"azz"
}
Dim sortedRevisions = testRevisions.OrderByDescending(Function(x) x, New RevisionComparer())
For Each item In sortedRevisions
Console.WriteLine(item)
Next
Console.WriteLine("-- DONE --")
Console.ReadKey()
End Sub
End Module
Which outputs:
cba
bca
azz
aza
aaa
bz
ba
az
aa
c
-- DONE --
Okay, now we are ready for the main event.
Requirements are:
1. Files are named in this format - drawing number_revision_page_date
.... example 0092933_C_1-2_061217.pdf
2. double letter revs - a to z - then repeat with aa, ab, ac...etc.
3. date is before revision??? (assumed as not clarified)
Here is a solution based on the above 3 identified requirements. (note: Easy to change)
First, we need to break the filename out into its parts:
Class FileType
Public Property ID As String
Public Property Name As String
Public Property Revision As String
Public Property [Date] As String
Public Property Pages As String
End Class
Using the
RevisionComparer
above we can now sort the filenames:
Module Module1
Sub Main()
Dim files = New List(Of String)() From {
"0092933_C_1-2_061117.pdf",
"0092933_Z_1-2_120617.pdf",
"0092933_AZ_1-2_120617.pdf",
"1092933_AB_1-2_061117.pdf",
"1092933_Z_1-2_120617.pdf",
"1092933_CZ_1-2_120617.pdf"
}
Dim data As New List(Of FileType)()
For Each file In files
Dim parts = IO.Path.GetFileNameWithoutExtension(file).Split(New Char() {"_"c}, StringSplitOptions.RemoveEmptyEntries)
If parts.Length = 4 Then
Dim fileDate = Nothing
DateTime.TryParse(parts(2), fileDate)
data.Add(New FileType() With {
.ID = parts(0),
.Revision = parts(1),
.[Date] = parts(2),
.Pages = parts(3),
.Name = file
})
End If
Next
Dim sorted = data.OrderByDescending(Function(x) x.[Date]) _
.ThenByDescending(Function(x) x.Revision, New RevisionComparer()) _
.GroupBy(Function(x) x.ID) _
.Select(Function(x) x.First())
For Each item In sorted
Console.WriteLine(item.Name)
Next
Console.WriteLine("-- DONE --")
Console.ReadKey()
End Sub
End Module
Which outputs:
1092933_CZ_1-2_120617.pdf
0092933_AZ_1-2_120617.pdf
-- DONE --
UPDATE: You ask for a "Linq only solution" and the answer is yes, you can avoid extra classes and make it one very long Linq query but then it comes down to readability and maintainability. The above solution ticks both of these boxes.
However, you asked for a one liner Linq query, so here it is, using the above Comparer due to the custom sorting requirement. All parts used are in the above more eloquent solution:
Dim sortedV2 = files.Select(Function(x) IO.Path.GetFileNameWithoutExtension(x).Split(New Char() {"_"c}, StringSplitOptions.RemoveEmptyEntries)) _
.OrderByDescending(Function(x) x(2)) _
.ThenByDescending(Function(x) x(1), New RevisionComparer()) _
.GroupBy(Function(x) x(0)) _
.Select(Function(x) x.First()) _
.Select(Function(x) String.Join("_", x) + ".pdf")
For Each item In sortedV2
Console.WriteLine(item)
Next
Note: the problem with this Linq one-liner solution is that if you have an incorrectly named file the Linq statement will throw an exception, however the above "original" solution won't.