Tyron78
Tyron78

Reputation: 4187

Alphanumerical sorting not working in Array

We have a directory, which features many subdirectories (one per day) with serveral files in it. Unfortunately, files can be resent - so a file of 2020-01-01 can be resend (with slightly different filename, since a timestamp is added to the filename) on 2020-02-03. The structure looks something like this:

So the AFile of 2020-08-01 has been resent on 2020-08-02 at 3 PM.

I am now trying to retrieve a list with the most recent file per day, so I built up an array and populated it with all files below TopDir (recurively). So far so good, all files are found:

$path = "Y:\";

$FileArray = @()
$FileNameArray = @()

$FileArrayCounter = 0

foreach ($item in Get-ChildItem $path -Recurse)
    {
      if ($item.Extension -ne "")
      {
        $StringPart1, $StringPart2, $StringPart3, $StringPart4 = $item.Name.Split('_');
        $FileNameShort = "{0}_{1}_{2}" -f $StringPart1.Trim(), $StringPart2.Trim(), $StringPart3.Trim();
        $FileNameShort = $FileNameShort.Trim().ToUpper();

        $FileArray += @{FileID = $FileArrayCounter; FileNameShort = $FileNameShort; FileName = $item.Name; FullName = $item.FullName; LastWriteTime = $item.LastWriteTime};
        $FileArrayCounter ++;
      }
    }


$FileArray = $FileArray | sort FileNameShort; #@{Expression={"FileNameShort"}; Ascending=$True} #, @{Expression={"LastWriteTime"}; Descending=$True}

foreach($f in $FileArray)
{
    Write-host($f.FileNameShort, $f.LastWriteTime)
}

Write-host($FileArrayCounter.ToString() + " Dateien gefunden");

The newly added column "FileNameShort" includes a substring of the filename. With this done, I receive two Rows for AFile_20200801:

However, when I try to sort my array (see above code), the output is NOT sorted by name. Instead I receive something like the following:

What I want to achieve is a sorting by FileNameShort ASCENDING and LastWriteTime DESCENDING.

What am I missing here?

Upvotes: 0

Views: 59

Answers (2)

AdminOfThings
AdminOfThings

Reputation: 25001

Your sort does not work because $FileArray is an array of hash tables. The syntax Sort FileNameShort is binding the FileNameShort property to the -Property parameter of Sort-Object. However, the hash table does not contain a property called FileShortName. You can see this if you run $FileArray[0] | Get-Member.

If you create them as custom objects, the simple sort syntax works.

$FileArray += [pscustomobject]@{FileID = $FileArrayCounter; FileNameShort = $FileNameShort; FileName = $item.Name; FullName = $item.FullName; LastWriteTime = $item.LastWriteTime}
$FileArray | Sort FileNameShort # This will sort correctly

As an aside, I do not recommend using += to seemingly add elements to an array. It is best to either output the results inside of your loop and save the loop results or create a list with an .Add() method. The problem with += is the current array is expanded into memory and those contents are then used to create a new array with the new items. As the array grows, it becomes increasingly non-performant. See below for a more efficient example.

$FileArray = foreach ($item in Get-ChildItem $path -Recurse)
    {
      if ($item.Extension -ne "")
      {
        $StringPart1, $StringPart2, $StringPart3, $StringPart4 = $item.Name.Split('_');
        $FileNameShort = "{0}_{1}_{2}" -f $StringPart1.Trim(), $StringPart2.Trim(), $StringPart3.Trim();
        $FileNameShort = $FileNameShort.Trim().ToUpper();
        # Outputting custom object here
        [pscustomobject]@{FileID = $FileArrayCounter; FileNameShort = $FileNameShort; FileName = $item.Name; FullName = $item.FullName; LastWriteTime = $item.LastWriteTime};
        $FileArrayCounter ++;
      }
    }

Upvotes: 1

Tyron78
Tyron78

Reputation: 4187

I just found the solution:

$FileArray = $FileArray | sort @{Expression={[string]$_.FileNameShort}; Ascending=$True}, @{Expression={[datetime]$_.LastWriteTime}; Descending=$True}

Still I don't know, why the first sorting did not work as expected.

Upvotes: 0

Related Questions