代码之家  ›  专栏  ›  技术社区  ›  flolilo

将数组作为值对哈希表排序

  •  4
  • flolilo  · 技术社区  · 8 年前

    描述 为了获得从一个函数到另一个函数的所有值,我选择使用 [hashtable]$FooBar -内部 $FooBar ,有多个阵列,例如 FullName OutputPath yyyy-mm-dd

    A短裤 可视化:

    $FooBar = @{}
    $FooBar.FullName = @()
    $FooBar.Size = @()
    $FooBar.Ext = @()
    Get-ChildItem | ForEach-Object {
        $FooBar.FullName += $_.FullName
        $FooBar.Size += $_.Length
        $FooBar.Ext += $_.Extension
    }
    

    # From:
    $FooBar
    Name                           Value
    ----                           -----
    fullname                       {D:\AAA.XYZ, D:\BBB.ZYX, D:\CCC.YZX}
    size                           {222, 111, 555}
    extension                      {.XYZ, .ZYX, .YZX}
    
    # To:
    $FooBar = $FooBar | Sort-Object -Property Size -Descending
    $FooBar
    Name                           Value
    ----                           -----
    fullname                       {D:\CCC.YZX, D:\AAA.XYZ, D:\BBB.ZYX}
    size                           {555, 222, 111}
    extension                      {.YZX, .XYZ, .ZYX}
    

    我试过了 $FooBar.GetEnumerator() | Sort-Object -Property Size ,但这并没有改变任何事情。谷歌提出了关于如何对一系列哈希表进行排序的建议,但在我的情况下,情况正好相反,我无法理解这一点,因为 我甚至不明白为什么这是一个问题 .

    免责声明

    3 回复  |  直到 8 年前
        1
  •  5
  •   Patrick Meinecke    8 年前

    我认为你想做的事情最简单的方法就是 Select-Object

    $fooBar = Get-ChildItem | Select-Object FullName, Size, Extension
    

    这将创建一个仅具有所需特性的新对象数组。这种方法有效而您的方法无效的原因是,排序对象适用于属性,而您指定的属性位于几个层之后。

    $fooBar = Get-ChildItem | Select-Object @{Name = 'SizeMB'; Expression = {$_.Size / 1MB}}
    

    或者使用手动创建新属性 [PSCustomObject]

    $fooBar = Get-ChildItem | ForEach-Object {
        [PSCustomObject]@{
            FullName = $_.FullName
            Extension = $_.Extension
            Size = $_.Size
        }
    }
    

    如果在对象最初创建后需要向其添加其他属性,则有几个选项。

    到目前为止,最常用的方法是使用 Add-Member cmdlet。

    $object | Add-Member -MemberType NoteProperty -Name NewProperty -Value 'MyValue'
    
    $object
    

    需要记住的一点是,默认情况下,此cmdlet不会返回任何内容。因此,如果您将上述语句放在函数的末尾,并且没有单独返回对象,那么您的函数将不会返回任何内容。确保您使用 -PassThru 命令)或随后调用变量(如上面的示例)

    选择对象

    使用计算特性添加成员时,可以选择以前的所有特性。记住,因为 选择对象 如果成功,则源对象中的所有方法都不会继续。

    $fooBar | Select-Object *, @{Name = 'NewProperty'; Expression = {'MyValue'}}
    

    这是我个人的最爱,但它仅限于PowerShell的更高版本,我还没有看到其他人使用它。

    $fooBar.psobject.Properties.Add([psnoteproperty]::new('NewProperty', 'MyValue'))
    $fooBar
    

    $fooBar.psobject.Methods 或键入至 $fooBar.psobject.Members 。我喜欢这种方法,因为它感觉更明确,而且用成员添加成员的方法感觉正确。

    总结

    如果可能的话,因为它是最常用的,因此具有更好的可读性和更多的人可以回答有关它的问题。

        2
  •  4
  •   Mathias R. Jessen    8 年前

    出于所有实际目的,我强烈建议您将所需的对象存储在单个数组中,对其进行一次排序,然后在需要时引用每个对象的各个属性:

    $FooBar = Get-ChildItem |Sort-Object -Property Length
    
    # Need the Extension property of the object at index 4?
    $FooBar[4].Extension
    

    要回答您的实际问题:

    Array.Sort() has an overload

    # Create hashtable of correlated arrays 
    $FooBar = @{}
    $FooBar.FullName = @()
    $FooBar.Size = @()
    $FooBar.Ext = @()
    # Types cast explicitly to avoid Array.Sort() calling .CompareTo() on the boxing object
    Get-ChildItem | ForEach-Object {
        $FooBar.FullName += [string]$_.FullName
        $FooBar.Size     += [int]$_.Length
        $FooBar.Ext      += [string]$_.Extension
    }
    
    # Define name of reference array property
    $SortKey = 'Size'
    
    # Sort all arrays except for the reference array
    $FooBar.Keys |Where-Object {$_ -ne $SortKey} |ForEach-Object {
        # Copy reference values to new array
        $Keys = $FooBar[$SortKey].Clone()
    
        # Sort values in target array based on reference values
        [array]::Sort($Keys,$FooBar[$_])
    }
    
    # Finally sort the reference array
    [array]::Sort($FooBar[$SortOn])
    

    上述方法仅在引用数组由值类型组成时有效

        3
  •  2
  •   G42    8 年前

    尝试:

    $FooBar = Get-Childitem
    $FooBar | Get-Member
    

    $Foobar 实际上包含的对象 FileInfo DirectoryInfo 键入,然后显示 Properties

    $FooBarSortedBySizeDesc  = $FooBar | Sort-Object Length -Descending
    $FooBarFullNamesOnly = $FooBar.FullName