PowerShell:如何获取管道集合的数量?
PowerShell: How to get count of piped collection?
假设我有一个生成对象集合的进程。举一个非常简单的例子,考虑 $(1 | get-member)
。我可以获得生成的对象数:
PS C:\WINDOWS\system32> $(1 | get-member).count
21
或者我可以用这些对象做点什么。
PS C:\WINDOWS\system32> $(1 | get-member) | ForEach-object {write-host $_.name}
CompareTo
Equals
...
只有21个对象,做上面的没有问题。但是,如果该过程生成数十万个对象怎么办?然后我不想 运行 这个过程一次只是为了计算对象然后再次 运行 它来执行我想对它们做的事情。那么我怎样才能得到一个集合中的对象计数呢?
A 之前被问过,接受的答案是在脚本块内使用一个计数器变量来处理集合。问题是我已经有了那个计数器,我想要的是检查那个计数器的结果是否正确。所以我不想只在脚本块内计数。我想要一个单独的、独立的度量方法来衡量我发送到管道中的集合的大小。我该怎么做?
如果需要处理和计数:
在 ForEach-Object
脚本块内进行自己的计数是避免分两次处理的最佳选择。
The problem is that I already have that counter and what I want is to check that the outcome of that counter is correct.
ForEach-Object
为每个输入对象可靠地调用,包括 $null
值,因此不需要仔细检查。
如果你想要更清晰的分离处理和计数,你可以将多个 -Process
脚本块传递给ForEach-Object
(在本例中,{ $_ + 1 }
是 input-processing 脚本块,{ ++$count }
是 input-counting一个):
PS> 1..5 | ForEach-Object -Begin { $count = 0 } `
-Process { $_ + 1 }, { ++$count } `
-End { "--- count: $count" }
2
3
4
5
6
--- count: 5
请注意,由于 ForEach-Object
的参数绑定中的一个怪癖,传递 -Begin
和 -End
脚本块实际上是 必需的 为了传递多个 -Process
(每个输入对象)块;如果您实际上不需要 -Begin
and/or -End
,请传递 $null
- 请参阅 GitHub issue #4513.
另请注意,$count
变量存在于调用者的范围内,而不是 ForEach-Object
调用的范围;也就是说,$count = 0
可能会更新一个预先存在的 $count
变量,如果它以前不存在,则在 ForEach-Object
调用之后继续存在。
如果只需要计数:
Measure-Object
是与管道中的大型流式输入集合一起使用的 cmdlet[1]:
以下示例一一生成 100,000 个整数,并 Measure-Object
对它们一一计数,而不是将整个输入收集到内存中。
PS> (& { $i=0; while ($i -lt 1e5) { (++$i) } } | Measure-Object).Count
100000
警告:Measure-Object
忽略输入集合中的 $null
值 - 参见 GitHub issue #10905.
请注意,虽然 计数 输入对象是 Measure-Object
的默认行为,但它也支持各种其他操作,例如 求和 -Sum
和 求平均值 (-Average
),可选择在单个调用中组合。
[1] Measure-Object
,作为 cmdlet,能够在 streaming 中处理输入] 时尚,这意味着它会在接收到对象时 一个一个地 计数对象,这意味着即使是非常大的流输入集(也一个一个地创建的,例如枚举具有 Import-Csv
) 的大型 CSV 文件的行可以在没有 运行 内存不足风险的情况下处理 - 无需加载输入集合 作为一个整体 到内存中。但是,如果 (a) 输入集合已经 是 在内存中,或者 (b) 它 可以适合 到内存并且性能很重要,那么使用(...).Count
.
假设我有一个生成对象集合的进程。举一个非常简单的例子,考虑 $(1 | get-member)
。我可以获得生成的对象数:
PS C:\WINDOWS\system32> $(1 | get-member).count
21
或者我可以用这些对象做点什么。
PS C:\WINDOWS\system32> $(1 | get-member) | ForEach-object {write-host $_.name}
CompareTo
Equals
...
只有21个对象,做上面的没有问题。但是,如果该过程生成数十万个对象怎么办?然后我不想 运行 这个过程一次只是为了计算对象然后再次 运行 它来执行我想对它们做的事情。那么我怎样才能得到一个集合中的对象计数呢?
A
如果需要处理和计数:
在 ForEach-Object
脚本块内进行自己的计数是避免分两次处理的最佳选择。
The problem is that I already have that counter and what I want is to check that the outcome of that counter is correct.
ForEach-Object
为每个输入对象可靠地调用,包括 $null
值,因此不需要仔细检查。
如果你想要更清晰的分离处理和计数,你可以将多个 -Process
脚本块传递给ForEach-Object
(在本例中,{ $_ + 1 }
是 input-processing 脚本块,{ ++$count }
是 input-counting一个):
PS> 1..5 | ForEach-Object -Begin { $count = 0 } `
-Process { $_ + 1 }, { ++$count } `
-End { "--- count: $count" }
2
3
4
5
6
--- count: 5
请注意,由于 ForEach-Object
的参数绑定中的一个怪癖,传递 -Begin
和 -End
脚本块实际上是 必需的 为了传递多个 -Process
(每个输入对象)块;如果您实际上不需要 -Begin
and/or -End
,请传递 $null
- 请参阅 GitHub issue #4513.
另请注意,$count
变量存在于调用者的范围内,而不是 ForEach-Object
调用的范围;也就是说,$count = 0
可能会更新一个预先存在的 $count
变量,如果它以前不存在,则在 ForEach-Object
调用之后继续存在。
如果只需要计数:
Measure-Object
是与管道中的大型流式输入集合一起使用的 cmdlet[1]:
以下示例一一生成 100,000 个整数,并 Measure-Object
对它们一一计数,而不是将整个输入收集到内存中。
PS> (& { $i=0; while ($i -lt 1e5) { (++$i) } } | Measure-Object).Count
100000
警告:Measure-Object
忽略输入集合中的 $null
值 - 参见 GitHub issue #10905.
请注意,虽然 计数 输入对象是 Measure-Object
的默认行为,但它也支持各种其他操作,例如 求和 -Sum
和 求平均值 (-Average
),可选择在单个调用中组合。
[1] Measure-Object
,作为 cmdlet,能够在 streaming 中处理输入] 时尚,这意味着它会在接收到对象时 一个一个地 计数对象,这意味着即使是非常大的流输入集(也一个一个地创建的,例如枚举具有 Import-Csv
) 的大型 CSV 文件的行可以在没有 运行 内存不足风险的情况下处理 - 无需加载输入集合 作为一个整体 到内存中。但是,如果 (a) 输入集合已经 是 在内存中,或者 (b) 它 可以适合 到内存并且性能很重要,那么使用(...).Count
.