我有这种格式的大型CSV文件(简化,更多列)
|Id|Category|Url|
用分号分隔的字段。假设我有一个包含以下数据的文件
id;category;categoryUrl 1;Xyz;http://1.com 2;Xyz;http://1.com 3;Xyz2;http://2.com 4;Xyz;http://2.com
我希望结果是
的结果id;category;categoryUrl 1;1;2 1;1;2 3;3;4 4;1;4
key;value 1;Xyz 2;http://1.com 3;Xyz2 4;http://2.com
问题的要点类别数据可以是更长的字符串,URL也是如此,实际上有几十列其中一些我想像这样预处理并离开按原样休息。作为一些预处理的一部分,我想用代理ID替换重复值,并将生成的CSV文件写入磁盘(而不是替换原始的)。然后,我还要将生成的代理ID与实际值一起写入另一个CSV文件。
我目前有以下脚本,但出于某种原因,它没有输出任何内容,而且我为何不这样做而傻眼了。有人可以帮忙吗?
$categoryTable = @{}
$categoryId = 0
Import-Csv "data.csv" -Delimiter ';' | ForEach-Object -PipelineVariable row {
if ($row.category) {
if (!$categoryTable.ContainsKey($row.category)) {
$categoryId += 1
$categoryTable.Add($row.category, $categoryId)
}
$category = $categoryTable.Get_Item($row.category)
$row.category = $category
}
if ($row.categoryUrl) {
if (!$categoryTable.ContainsKey($row.categoryUrl)) {
$categoryId += 1
$categoryTable.Add($row.categoryUrl, $categoryId)
}
$categoryUrl = $categoryTable.Get_Item($row.categoryUrl)
$row.categoryUrl = $categoryUrl
}
} | Export-Csv -Path data_categorized.csv -Force -NoTypeInformation
([PSCustomObject]$categoryTable) | Export-Csv -Path categoryIds.csv -Force -NoTypeInformation
<编辑:
来自 wOxxOm 的提示Ansgar的解决方案已经完成了!为了其他人的利益,我将完整地包含该脚本
$categoryTable = @{}
Import-Csv "data.csv" -Delimiter ';' -PipelineVariable row | ForEach-Object {
if($row.category) {
if(-not $categoryTable.ContainsKey($row.category)) {
$categoryTable[$row.category] = $categoryTable.Count + 1
}
$row.category = $categoryTable[$row.category]
}
if($row.categoryUrl) {
if(-not $categoryTable.ContainsKey($row.categoryUrl)) {
$categoryTable[$row.categoryUrl] = $categoryTable.Count + 1
}
$row.categoryUrl = $categoryTable[$row.categoryUrl]
}
$row
} | Export-Csv -Path categoryIds.csv -Delimiter ';' -Force -NoTypeInformation
$categoryTable.GetEnumerator() | Select-Object @{n='key';e={$_.Value}}, @ {n='value';e={$_.Key}} | Export-Csv -Path categoryIds.csv -Delimiter ';' -Force -NoTypeInformation
答案 0 :(得分:3)
你得到一个空文件data_categorized.csv
,因为你不输出ForEach-Object
循环中的行,并且在注释中指出@wOxxOm,由{定义的变量{3}}用于下游cmdlet。将$row
替换为-PipelineVariable
$_
,并在循环结束时添加$_
:
... | ForEach-Object {
...
$_
} | Export-Csv ...
文件categoryIds.csv
应包含数据,但不包含您期望的格式。将哈希表投射到自定义对象将为您提供此输出
1,2,3,4 Xyz,http://1.com,Xyz2,http://2.com
而不是此输出:
key,value 1,Xyz 2,http://1.com 3,Xyz2 4,http://2.com
要获得后者,你需要这样的东西:
$categoryTable.GetEnumerator() | Select-Object Key, Value | Export-Csv ...
此外,您将类别ID定义为哈希表的值,并将类别和类别URL定义为键,因此您实际上可以获得此输出:
key,value Xyz,1 http://1.com,2 Xyz2,3 http://2.com,4
如果您想要key
列中的ID,则需要重新标记字段,例如与current object variable:
$categoryTable.GetEnumerator() |
Select-Object @{n='key';e={$_.Value}}, @{n='value';e={$_.Key}} |
Export-Csv ...
作为旁注:您的哈希表处理过于复杂。这样的事情就足够了:
if (-not $categoryTable.ContainsKey($row.category)) {
$categoryTable[$_.category] = $categoryTable.Count+1
}
$_.category = $categoryTable[$_.category]
另请注意,导出不指定自定义分隔符,因此输出文件将以逗号分隔,而不是以分号分隔。将-Delimiter ';'
添加到Export-Csv
语句中以解决此问题。