我正在尝试创建一个PowerShell脚本,将CSV文件从列转换为行。
我找到了相反的例子(将基于行的CSV转换为列),但我没有在列到行中找到任何内容。我的问题是我不确切知道有多少列。我尝试将行调整为列到行但不成功。
$a = Import-Csv "input.csv"
$a | FT -AutoSize
$b = @()
foreach ($Property in $a.Property | Select -Unique) {
$Props = [ordered]@{ Property = $Property }
foreach ($Server in $a.Server | Select -Unique){
$Value = ($a.where({ $_.Server -eq $Server -and
$_.Property -eq $Property })).Value
$Props += @{ $Server = $Value }
}
$b += New-Object -TypeName PSObject -Property $Props
}
$b | FT -AutoSize
$b | Out-GridView
$b | Export-Csv "output.csv" -NoTypeInformation
例如,我的CSV可能如下所示:
"ID","DATA1" "12345","11111" "54321","11111" "23456","44444"
或者这个(列数可以变化):
"ID","DATA1","DATA2","DATA3" "12345","11111","22222","33333" "54321","11111",, "23456","44444","55555",
我想让脚本像这样转换它:
"ID","DATA" "12345","11111" "12345","22222" "12345","33333" "54321","11111" "23456","44444" "23456","55555"
答案 0 :(得分:1)
诀窍是查询表的成员以获取列名。一旦你这样做,其余的就很简单了:
function Flip-Table ($Table) {
Process {
$Row = $_
# Get all the columns names, excluding the ID field.
$Columns = ($Row | Get-Member -Type NoteProperty | Where-Object Name -ne ID).Name
foreach ($Column in $Columns) {
if ($Row.$Column) {
$Properties = [Ordered] @{
"ID" = $Row.ID
"DATA" = $Row.$Column
}
New-Object PSObject -Property $Properties
}
}
# Garbage collection won't kick in until the end of the script, so
# invoke it every 100 input rows.
$Count++;
if (($Count % 100) -eq 0) {
[System.GC]::GetTotalMemory('forceFullCollection') | out-null
}
}
}
Import-Csv input.csv | Flip-Table | Export-Csv -NoTypeInformation output.csv
答案 1 :(得分:1)
嗯,这是我的。我不像其他人那样喜欢:
$in = Get-Content input.csv | Select -Skip 1
$out = New-Object System.Collections.ArrayList
foreach($row in $in){
$parts = $row.Split(',')
$id = $parts[0]
foreach($data in $parts[1..$parts.Count]){
if($data -ne '' -AND $data -ne $null){
$temp = New-Object PSCustomObject -Property @{'ID' = $id;
'Data' = $data}
$out.Add($temp) | Out-Null
}
}
}
$out | Export-CSV output.csv -NoTypeInformation
答案 2 :(得分:0)
你可以做这样的事情
# Convert csv to object
$csv = ConvertFrom-Csv @"
"ID","DATA1","DATA2","DATA3"
"12345","11111","22222","33333"
"54321","11111",,
"23456","44444","55555"
"@
# Ignore common members and the ID property
$excludedMembers = @(
'GetHashCode',
'GetType',
'ToString',
'Equals',
'ID'
)
$results = @()
# Iterate around each csv row
foreach ($row in $csv) {
$members = $row | Get-Member
# Iterate around each member from the 'row object' apart from our
# exclusions and empty values
foreach ($member in $members |
Where { $excludedMembers -notcontains $_.Name -and $row.($_.Name)}) {
# add to array of objects
$results += @{ ID=$row.ID; DATA=$row.($member.Name)}
}
}
# Write the csv string
$outstring = "ID,DATA"
$results | foreach { $outstring += "`n$($_.ID),$($_.DATA)" }
# New csv object
$csv = $outstring | ConvertFrom-Csv
可能不是最优雅的解决方案,但应该做你需要的
我留下了一些解释它的作用的评论
答案 3 :(得分:0)
如果您只想接受有限数量的DATA
列(例如5),则可以执行以下操作:
ForEach ($i in 1..5) {$CSV | ? {$_."Data$i"} | Select ID, @{N='Data'; E={$_."Data$i"}}}
如果您有无限数量的DATA
列:
ForEach ($Data in ($CSV | Select "Data*" -First 1).PSObject.Properties.Name) {
$CSV | ? {$_.$Data} | Select ID, @{N='Data'; E={$_.$Data}}
}