不同长度的数组到一个 CSV

问题描述 投票:0回答:3

如果您有多个不同长度的数组,如何在 powershell 中将它们导出到单个 csv?

Array1 = 1,2,3 
Array2 = Bob,smithy,Alex,Jeremy 
Array3 = yes,no

输出 CSV

号码名称有效
————————————————————
1 鲍勃 是的
2 铁匠铺 没有
3 亚历克斯
       杰里米

基本上每个数组都位于其自己的标题列中。

尝试过像

这样的线路
Array1 | Select-Object Number | export-csv -Path C:\Path

这适用于单个数组到单个 csv 文件

但是如果我尝试

Array1, Array2, Array3 | Select-Object Number, Name, Valid | export-csv -Path C:\Path

我只得到标题名称,列中没有值

arrays powershell export-to-csv
3个回答
7
投票

一种方法是使用

for
循环

$Array1 = 1, 2, 3
$Array2 = 'Joe Bloggs', 'John Doe', 'Jane Doe'
$Array3 = 'Yes', 'No'

$export = for($i = 0; $i -lt [Linq.Enumerable]::Max([int[]] ($Array1.Count, $Array2.Count, $Array3.Count)); $i++) {
    [pscustomobject]@{
        Number = $Array1[$i]
        Name   = $Array2[$i]
        Valid  = $Array3[$i]
    }
}
$export | Export-Csv path\to\csv.csv -NoTypeInformation

另一个使用函数的示例,逻辑或多或少相同,只是涉及更多开销,因为该函数可以处理来自管道的无限数量的数组。

function Join-Array {
    [CmdletBinding()]
    param(
        [parameter(ValueFromPipeline, Mandatory)]
        [object[]] $InputObject,

        [parameter(Mandatory, Position = 0)]
        [string[]] $Columns
    )

    begin {
        $inputDict = [ordered]@{}
        $index = 0
    }
    process {
        try {
            if ($MyInvocation.ExpectingInput) {
                return $inputDict.Add($Columns[$index++], $InputObject)

            }

            foreach ($item in $InputObject) {
                $inputDict.Add($Columns[$index++], $item)
            }
        }
        catch {
            if ($_.Exception.InnerException -is [ArgumentNullException]) {
                $errorRecord = [Management.Automation.ErrorRecord]::new(
                    [Exception] 'Different count between input arrays and Columns.',
                    'InputArrayLengthMismatch',
                    [Management.Automation.ErrorCategory]::InvalidOperation,
                    $InputObject
                )
                $PSCmdlet.ThrowTerminatingError($errorRecord)
            }
            $PSCmdlet.ThrowTerminatingError($_)
        }
    }
    end {
        foreach ($pair in $inputDict.GetEnumerator()) {
            $count = $pair.Value.Count
            if ($count -gt $max) {
                $max = $count
            }
        }

        for ($i = 0; $i -lt $max; $i++) {
            $out = [ordered]@{}
            foreach ($column in $inputDict.PSBase.Keys) {
                $out[$column] = $inputDict[$column][$i]
            }
            [pscustomobject] $out
        }
    }
}

使用非常简单,要连接/压缩的数组可以通过管道传递,并按位置定义所需的列名称:

$Array1 = 1, 2, 3
$Array2 = 'Joe Bloggs', 'John Doe', 'Jane Doe'
$Array3 = 'Yes', 'No'
$Array4 = 'hello', 'world', 123, 456

$Array1, $Array2, $Array3, $Array4 | Join-Array Number, Name, Valid, Test |
    Export-Csv path\to\csv.csv -NoTypeInformation

2
投票

相当长一段时间以来,我一直在维护

Join-Object script
/
Join-Object Module
(另请参阅:在 PowerShell 中,将两个表合并为一个表的最佳方法是什么?)。
它的主要目的是基于由
-on
参数定义的相关列(又名属性),使用用户(又名脚本编写者)友好的语法连接表(也称为对象列表),其中有尽可能多的连接选项。这导致了一些可以在您的特定请求中使用的隐式功能:

  • 如果没有定义关系(省略
    -on
    参数),则假设您想要对表(也称为列表)进行并排连接
    • 如果表(或列表)大小不相等,则公共(内部)联接将在任一列表结束时结束。另一方面,完整连接(例如
      FullJoin-Object
      别名
      FullJoin
      或左或右连接)将连接完整的相应列表
  • 标量数组(例如字符串而不是自定义对象)被连接为对象列表,其中(默认)列(又名属性)名称为
    Value
    • 如果两侧都包含标量列表,则输出将是每个左侧和右侧项目的
      [Collections.ObjectModel.Collection[psobject]]
      列表,包含这些项目。
  • 连接命令可以链接:
    ... | Join ... | Join ...
  • 如果表(又名列表)中提供的列(又名属性)重叠,默认情况下它们将合并在一个数组(
    <property name> = <left property value>, <right property value>
    )中,也可以使用
    -Name 将这些项目分配给特定名称(前缀) 
    参数。此参数可与链中的每个连接命令一起使用。

总而言之,这意味着您可以使用以下命令行来实现您的任务:

$Array1 | FullJoin $Array2 | FullJoin $Array3 -Name Number, Name, Valid
Number Name       Valid
------ ----       -----
     1 Joe Bloggs Yes
     2 John Doe   No
     3 Jane Doe

更新(2023-22-06)

自版本

3.8.1
起,可以动态添加数组(从空数组启动器开始),另请参阅 issue #42。以这个问题为例:

作为新的转置锯齿状数组:

$dummy = @(("a","b","c"),("1","2","3"),("John","Jane","Smith"))
$dummy |Foreach-Object { $a = @() } { $a = $a | FullJoin $_ }

$a.ForEach{ $_ -Join '|' }

a|1|John
b|2|Jane
c|3|Smith

转换为对象集合:

$a | FullJoin @() -Name foo, bar, baz

foo bar baz
--- --- ---
a   1   John
b   2   Jane
c   3   Smith

动态命名:

$dummy |Foreach-Object { $a = @(); $n = 1 } { $a = $a | FullJoin $_ -Name "Name$(($n++))" }
$a

Name1 Name2 Name3
----- ----- -----
a     1     John
b     2     Jane
c     3     Smith

0
投票

您需要重构数据以将其转换为一个数组(此处以伪 json 形式呈现):

[ 
  {"1", "Bob", "Yes"}, 
  {"2", "Smithy", "no"}, 
  {"3", "Alex", ""}, 
  {"", "Jeremy", ""} 
]

请注意缺失的字段如何仍然显示为空占位符。

一旦您以这种方式转换数据,将其写入 CSV 文件就很简单了,许多其他任务也是如此(这是首先构建事物的更好方法)。

© www.soinside.com 2019 - 2024. All rights reserved.