Select-对象-唯一

Select-Object -Unique

我的理解是

$list = @('1', '2', '3', '1', '4')
Select-Object -InputObject $list -Unique

应该return一个只有 4 个元素的数组,跳过第二个不唯一的“1”。

但我正在取回所有 5 个元素。我理解错了吗,或者 Select-Object 有错误,至少在我正在测试的 PS 5.1 中是这样?

  • 只有少数例外,特别是 ConvertFrom-CsvGet-RandomJoin-StringGet-Member, -InputObject 参数应被视为实现细节,其目的是促进管道输入,因此 不应 直接使用 。 built-in cmdlet 属于以下类别之一:

    • 类别 A:select 几个 cmdlet,例如 Get-Member 有用 区分在将输入 collection 作为 参数 传递给 -InputObject 和隐式枚举 collection 的 元素 之间通过管道。

    • 类别 B:select 几个 cmdlet,例如 ConvertFrom-Csv(但 不是 ConvertTo-Csv)、Get-RandomJoin-StringOut-String,或者具有 array 值的 -InputObject 参数(例如-InputObject <psobject[]>) 或 对传递给其 标量 InputObject 参数的参数显式执行枚举(例如,-InputObject <psobject>).

      • 对于 flat 输入 collections(这是典型的)[1],这样的 cmdlet 有效地处理直接 argument-passing 与管道输入相同 - 除了直接 argument-passing 是 快得多 ;见下文。
    • 类别 C:不幸的是,大多数 cmdlet 都有标量 -InputObject 参数 进程collections作为一个整体传递给-InputObject,这有效地使参数直接argument-passing无用。

  • 有点不幸,因为传递了一个已经in-memorycollectionas一个 cmdlet 的参数 比通过管道一个一个地发送它的元素要快得多 .

    • 例如,比较使用直接 argument-passing 或管道将 100 万个项目传递给 Get-Random 的运行时间:Get-Random -InputObject (1..1e6)
      1..1e6 | Get-Random

    • 请注意,此优化有时也可用于 other cmdlet 参数;值得注意的是,您可以将 collection 传递给 Set-Content-Value 参数,作为管道传递的替代方法,这大大加快了写入速度。


这是 built-in cmdlet 的分类和字母排序列表:

  • 类别 A:管道输入和显式输入之间的有用区别 -InputObject 使用:处理 collections 作为一个整体 ,通过他们 -InputObject;要一一处理它们的元素,请使用管道:

    • Add-Member
    • Export-Clixml
    • Get-Member
    • Trace-Command
  • 类别 B:flat 的有用等价物 collections:您可以将 flat collections 直接传递给 -InputObject 加快处理速度:

    • ConvertFrom-Csv
    • Format-Custom
    • Format-List
    • Format-Table
    • Format-Wide
    • Get-Random
    • Join-String
    • Out-Host
    • Out-String
  • 类别 C:无用区别:直接 -InputObject 使用毫无意义:

    • ConvertTo-Csv
    • ConvertTo-Html
    • ConvertTo-Xml
    • Export-Csv
    • ForEach-Object
    • Format-Hex
    • Get-Unique
    • Group-Object
    • Invoke-Command
    • Measure-Command
    • Measure-Object
    • Select-Object
    • Select-String
    • Sort-Object
    • Start-Job
    • Update-List
    • Where-Object

[1] nested collection 管道输入和 -InputObject use 之间的处理差异:

那些枚举其 -InputObject 参数的 cmdlet 仅对输入 collection 执行 一个 枚举级别,并保留 嵌套 collections as-is.

相比之下,管道的使用可以导致 两个 级迭代,如以下 Join-String 示例所示:

PS> Join-String -InputObject ('foo', ('bar', 'baz'))
foobar baz

foo 和嵌套数组的字符串化 作为一个整体 - bar baz - 加入了。

PS> 'foo', ('bar', 'baz') | Join-String
foobarbaz

foo 和嵌套数组的 枚举元素 已连接。

原因是在这种情况下发生 两次 处理传递,这是由于管道的枚举行为:首先传递 foo,然后传递嵌套数组 'bar', 'baz',并且 single-level 枚举在 each 上执行,所有输入 objects 的结果被合并。