-
-
Save AgainPsychoX/4e6aabc8e8832a2afde1386d038eda31 to your computer and use it in GitHub Desktop.
Sorting the same way Windows Explorer does
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$array = @('1a2a5773', '0fe68296', '01b7f045') | |
$expected = @('0fe68296', '01b7f045', '1a2a5773') | |
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
Write-Host 'Bad:' # from https://stackoverflow.com/a/5429048/4880243 | |
$array | Sort-Object { [regex]::Replace($_, '\d+', { $args[0].Value.PadLeft(20) }) } | |
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
Add-Type -TypeDefinition @" | |
using System.Runtime.InteropServices; | |
public static class NaturalSort | |
{ | |
[DllImport("Shlwapi.dll", CharSet = CharSet.Unicode)] | |
private static extern int StrCmpLogicalW(string psz1, string psz2); | |
public static string[] Sort(string[] array) | |
{ | |
System.Array.Sort(array, (psz1, psz2) => StrCmpLogicalW(psz1, psz2)); | |
return array; | |
} | |
} | |
"@ | |
Write-Host 'Good:' # from https://stackoverflow.com/a/65527560/4880243 | |
[NaturalSort]::Sort($array) | |
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
function NaturalSort-Object { | |
[CmdletBinding(PositionalBinding=$false)] | |
param ( | |
[Parameter(ValueFromPipeline)] | |
$InputObject, | |
[Parameter(Position=0)] | |
[string]$PropertyOrExpression, | |
[switch]$Descending | |
) | |
begin { | |
Add-Type -TypeDefinition @" | |
using System.Runtime.InteropServices; | |
using System.Collections; | |
public static class Shlwapi_StrCmpLogicalW | |
{ | |
[DllImport("Shlwapi.dll", CharSet = CharSet.Unicode)] | |
private static extern int StrCmpLogicalW(string psz1, string psz2); | |
public class Comparer : IComparer | |
{ | |
int IComparer.Compare(object x, object y) | |
{ | |
return StrCmpLogicalW(x.ToString(), y.ToString()); | |
} | |
} | |
public class ReversedComparer : IComparer | |
{ | |
int IComparer.Compare(object x, object y) | |
{ | |
return StrCmpLogicalW(y.ToString(), x.ToString()); | |
} | |
} | |
public static TValue[] Sorted<TValue>(string[] keys, TValue[] items) | |
{ | |
System.Array.Sort(keys, items, new Comparer()); | |
return items; | |
} | |
public static TValue[] SortedDescending<TValue>(string[] keys, TValue[] items) | |
{ | |
System.Array.Sort(keys, items, new ReversedComparer()); | |
return items; | |
} | |
} | |
"@ | |
$keys = @() | |
$items = @() | |
} | |
process { | |
if ($PropertyOrExpression -is [string]) { | |
$keys += ($InputObject | Select-Object -Property $Property) | |
} | |
elseif ($PropertyOrExpression -is [scriptblock]) { | |
$keys += ($InputObject | Select-Object $PropertyOrExpression) | |
} | |
else { | |
throw 'No property or expression provided' | |
} | |
$items += $_ | |
} | |
end { | |
if ($Descending) { | |
return [Shlwapi_StrCmpLogicalW]::SortedDescending($keys, $items) | |
} | |
else { | |
return [Shlwapi_StrCmpLogicalW]::Sorted($keys, $items) | |
} | |
} | |
} | |
Write-Host 'Good (my take):' | |
$array | NaturalSort-Object | |
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
# Bad: | |
# 0fe68296 | |
# 1a2a5773 | |
# 01b7f045 | |
# Good: | |
# 0fe68296 | |
# 01b7f045 | |
# 1a2a5773 | |
# Good (my take): | |
# 0fe68296 | |
# 01b7f045 | |
# 1a2a5773 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment