在 powershell 中对数组(或列表)进行切片的更好方法 [英] A better way to slice an array (or a list) in powershell

查看:140
本文介绍了在 powershell 中对数组(或列表)进行切片的更好方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我如何以 CSV 文件格式为每个用户导出 30 个用户的邮件地址.我已经试过了

    $users = Get-ADUser -Filter * -Properties Mail 
    $nbCsv = [int][Math]::Ceiling($users.Count/30)
    For($i=0; $i -le $nbCsv; $i++){
        $arr=@()
        For($j=(0*$i);$j -le ($i + 30);$j++){
            $arr+=$users[$j]
        }
        $arr|Export-Csv -Path ($PSScriptRoot + "\ASSFAM" + ("{0:d2}" -f ([int]$i)) + ".csv") -Delimiter ";" -Encoding UTF8 -NoTypeInformation
    }

它有效,但我认为有更好的方法来完成这项任务.你有什么想法吗?

It works but, i think there is a better way to achieve this task. Have you got some ideas ?

谢谢.

推荐答案

Bacon Bits 的有用回答 展示了如何简化您的代码在 .. 的帮助下,范围运算符,但如果有一个通用的分块(分区、批处理)机制;但是,从 PowerShell 7.0 开始,没有内置功能.

Bacon Bits' helpful answer shows how to simplify your code with the help of .., the range operator, but it would be nice to have a general-purpose chunking (partitioning, batching) mechanism; however, as of PowerShell 7.0, there is no built-in feature.

此 GitHub 功能建议 建议添加 -ReadCount ; 参数给 Select-Object,类似于已经为 Get-Content 定义的同名参数.
如果您希望看到此功能得到实施,请在此处显示您对链接问题的支持.

This GitHub feature suggestion proposes adding a -ReadCount <int> parameter to Select-Object, analogous to the parameter of the same name already defined for Get-Content.
If you'd like to see this feature implemented, show your support for the linked issue there.

使用该功能后,您可以执行以下操作:

With that feature in place, you could do the following:

$i = 0
Get-ADUser -Filter * -Properties Mail |
  Select-Object -ReadCount 30 |  # WISHFUL THINKING: output 30-element arrays
   ForEach-Object {
     $_ | Export-Csv -Path ($PSScriptRoot + "\ASSFAM" + ("{0:d2}" -f ++$i) + ".csv") -Delimiter ";" -Encoding UTF8 -NoTypeInformation
   }

在此期间,您可以使用自定义函数 Select-Chunk(源代码如下):将 Select-Object -ReadCount 30 替换为 Select-Chunk -ReadCount 30 在上面的代码片段中.

In the interim, you could use custom function Select-Chunk (source code below): replace Select-Object -ReadCount 30 with Select-Chunk -ReadCount 30 in the snippet above.

以下是其工作原理的简单演示:

Here's a simpler demonstration of how it works:

PS> 1..7 | Select-Chunk -ReadCount 3 | ForEach-Object { "$_" }

1 2 3
4 5 6
7

上面显示 ForEach-Object 脚本块接收以下内容三个数组,通过$_,依次:
1, 2, 3, 4, 5, 6, 7

The above shows that the ForEach-Object script block receive the following three arrays, via $_, in sequence:
1, 2, 3, 4, 5, 6, and , 7

(当您对数组进行字符串化时,默认情况下您会得到一个以空格分隔的元素列表;例如, "$(1, 2, 3)" 产生 1 2 3).

(When you stringify an array, by default you get a space-separated list of its elements; e.g., "$(1, 2, 3)" yields 1 2 3).

实现使用[System.Collections.Generic.Queue[object]] 以固定大小批量收集输入的实例.

The implementation uses a [System.Collections.Generic.Queue[object]] instance to collect the inputs in batches of fixed size.

function Select-Chunk {
  <#
  .SYNOPSIS
  Chunks pipeline input.

  .DESCRIPTION
  Chunks (partitions) pipeline input into arrays of a given size.

  By design, each such array is output as a *single* object to the pipeline,
  so that the next command in the pipeline can process it as a whole.

  That is, for the next command in the pipeline $_ contains an *array* of
  (at most) as many elements as specified via -ReadCount.

  .PARAMETER InputObject
  The pipeline input objects binds to this parameter one by one.
  Do not use it directly.

  .PARAMETER ReadCount
  The desired size of the chunks, i.e., how many input objects to collect
  in an array before sending that array to the pipeline.

  0 effectively means: collect *all* inputs and output a single array overall.

  .EXAMPLE
  1..7 | Select-Chunk 3 | ForEach-Object { "$_" }

  1 2 3
  4 5 6
  7

  The above shows that the ForEach-Object script block receive the following
  three arrays: (1, 2, 3), (4, 5, 6), and (, 7)
  #>

  [CmdletBinding(PositionalBinding = $false)]
  [OutputType([object[]])]
  param (
    [Parameter(ValueFromPipeline)] 
    $InputObject
    ,
    [Parameter(Mandatory, Position = 0)]
    [ValidateRange(0, [int]::MaxValue)]
    [int] $ReadCount
  )

  begin {
    $q = [System.Collections.Generic.Queue[object]]::new($ReadCount)
  }

  process {
    $q.Enqueue($InputObject)
    if ($q.Count -eq $ReadCount) {
      , $q.ToArray()
      $q.Clear()
    }
  }

  end {
    if ($q.Count) {
      , $q.ToArray()
    }
  }

}

这篇关于在 powershell 中对数组(或列表)进行切片的更好方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆