I want a list of the unique directories that contain a file matching subjectPattern. I can get the list, but to get the unique directories, I need to sort it. But because the list is of type Collections.Generic.List[DirectoryInfo], I'm having trouble finding a working API.
function Get-Containers([Parameter(Mandatory)][string]$subjectPattern) {
#NOTE: The class for directories is System.IO.DirectoryInfo, the class for files is System.IO.FileInfo
$fatList = New-Object Collections.Generic.List[System.IO.DirectoryInfo]
$result = New-Object Collections.Generic.List[System.IO.DirectoryInfo]
foreach ($leafName in (get-childitem -recurse -force -path . -include $subjectPattern)) {
$fatList += (Get-Item $leafName).Directory
}
#Get-Unique only works on sorted collections, Sort-Object won't work without a Property,
# but "FullName" is not a property of Collections.Generic.List
# Furthermore, Sort() is not a method of [System.IO.DirectoryInfo]
$result = ($fatList.Sort() | Get-Unique )
return $result
}
How do I sort, then get unique items in Collections.Generic.List[System.IO.DirectoryInfo] ?
From your inline comments:
That's fine, we're not sorting multiple lists, we're sorting multiple
DirectoryInfoobjects that happen to be contained in a single list.The big question is: Do you need to sort in-place?
Sorting "in-place" means re-arranging the objects inside the list, so that the list itself retains the new sort order and its identity. This is usually less resource-intensive, but slightly complicated in PowerShell.
The alternative is to enumerate the items in the list, sort them externally and then (optionally) wrapping the re-ordered items in a new list - much easier to implement, but at a resource cost (which you may or may not notice depending on the size of the collection and the complexity of the comparison).
Sorting in-place
In order to sort multiple
DirectoryInfoobjects, we need a way to instruct theList[DirectoryInfo].Sort()method on how to compare the objects to each other and determine which comes before or after the other in the sort order.Looking at the
Sort()method overloads gives us a clue:So we need something that implements the generic interface
IComparer[T].Using PowerShell's ability to define new types at runtime using the
classkeyword, we can do:... and now we can sort the list in-place based on a property name, just like with
Sort-Object:Sort externally
Now that we know the trials we must go through to sort a generic collection in-place, let's review the process of sorting the collection externally:
If we need the resulting (now sorted) collection to also be of type
[List[Directory]], we can either clear and re-populate the original list:... or we can create a new
[List[DirectoryInfo]]instance:How about a
SortedSet[DirectoryInfo]?As already suggested, a "set" might be a better collection type for the purpose of only storing unique items.
The
HashSet[T]type is an unordered set, but .NET also comes with aSortedSet[T]type - and you won't believe what it requires to implement the sort order - that's right, anIComparer[T]! :-)In this case, we'll want to inject the comparer into the constructor when we create the set:
As you can see, there are multiple options available, with varying degrees of complexity and performance characteristics. It's not entirely clear from your question why you're using a generic list or why you insist on sorting it using
List.Sort(), so my recommendation would be to test them all out and see what works best for you