合并两个 CSV 文件,同时添加新条目和覆盖现有条目
Merge two CSV files while adding new and overwriting existing entries
我有一个 configuration.csv
包含这样的模板数据:
| path | item | value | type |
|------------|-------|--------|------|
| some/path | item1 | value1 | ALL |
| some/path | item2 | UPDATE | ALL |
| other/path | item1 | value2 | SOME |
和 customization.csv
具有特定于服务的配置:
| path | item | value | type |
|------------|-------|--------|------|
| some/path | item2 | value3 | ALL |
| new/path | item3 | value3 | SOME |
我的目标是合并它们并最终得到这样的结果:
| path | item | value | type |
|------------|-------|--------|------|
| some/path | item1 | value1 | ALL |
| some/path | item2 | value3 | ALL |
| other/path | item1 | value2 | SOME |
| new/path | item3 | value3 | SOME |
这应该添加任何新条目并更新任何现有条目。没有一列可以用于唯一标识 - path
和 item
都需要合并,因为它们保证是唯一的。
经过大量搜索,我认为无需重新创建管理框架即可操作条目的最简单方法是通过 hashtable。在此过程中,我不得不考虑两种极端情况:
- 值中的附加逗号
- 空值
我得到的最终解决方案是这样的:
$configuration = Import-Csv .\configuration.csv
$customization = Import-Csv .\customization.csv
$merged = New-Object System.Collections.ArrayList
$hashTable = @{}
#initializing the hashTable with the defaults
foreach ($entry in $configuration)
{
$hashTable[$entry.path + ',' + $entry.item] = $entry.value + ',' + $entry.type
}
#updating the hashTable with customization that add or overwrite existing entries
foreach ($entry in $customization)
{
$hashTable[$entry.path + ',' + $entry.item] = $entry.value + ',' + $entry.type
}
#the regex handles multiple commas and empty values.
#It returns an empty string before and after group so we start from 1
foreach ($key in $hashTable.keys)
{
$psobject = [PSCustomObject]@{
path = ($key -split '(.*),(.*)')[1]
item = ($key -split '(.*),(.*)')[2]
value = ($hashTable[$key] -split '(.*),(.*)')[1]
type = ($hashTable[$key] -split '(.*),(.*)')[2]
}
[void] $merged.Add($psobject)
}
Write-Output $merged
导入后,我将 configuration.csv
转换为哈希表,其键由 path
和 value
组成。然后,我使用相同的哈希表对 customization.csv
执行相同的操作,该哈希表会覆盖任何现有的 key
值或将它们添加为新值。
第三个循环将 hashTable 转换为 PSCustomObject
,类似于 Import-Csv
所做的。我拆分了每个 key
和 value
属性,同时考虑了多个逗号和空值。
注意:正则表达式将在最后一次出现分隔符时拆分(这里是逗号,但你可以 select 任何东西,真的)。如果要在第一个拆分,可以使用(.*?),(.*)
。在我的例子中,只有 value
列可以包含分隔符的实例。
如果 CSV 文件有唯一列,则可以使用类似于 的解决方案。
另一种方法是将键设置为所有列的总和,这将过滤掉 CSV 中的所有重复项,但拆分可能会变得棘手,具体取决于列中的值。
我建议使用 Compare-Object
,因为来自 customization.csv
的值应持续使用此文件值作为 -ReferenceObject
## Q:\Test19\SO_54948111.ps1
$conf = Import-Csv '.\configuration.csv'
$cust = Import-Csv '.\customization.csv'
$NewData = Compare-Object -ref $cust -diff $conf -Property path,item -PassThru -IncludeEqual|
Select-Object -Property * -ExcludeProperty SideIndicator
$NewData
$NewData |Export-Csv '.\NewData.csv' -NoTypeInformation
示例输出
> Q:\Test19\SO_54948111.ps1
path item value type
---- ---- ----- ----
some/path item2 value3 ALL
some/path item1 value1 ALL
other/path item1 value2 SOME
new/path item3 value3 SOME
您的想法“使用相同的哈希表来覆盖任何现有的键值或将它们添加为新的。”只有在 path, item
在每一侧都是唯一的情况下才有效因为您还将覆盖所有重复项...
考虑这个 Join-Object
cmdlet。
$configuration =
ConvertFrom-SourceTable
'
| path | item | value | type |
|------------|-------|--------|------|
| some/path | item1 | value1 | ALL |
| some/path | item2 | UPDATE | ALL |
| other/path | item1 | value2 | SOME |
| other/path | item1 | value3 | ALL |
'
$customization=
ConvertFrom-SourceTable
'
| path | item | value | type |
|------------|-------|--------|------|
| some/path | item2 | value3 | ALL |
| new/path | item3 | value3 | SOME |
| new/path | item3 | value4 | ALL |
'
使用 Merge-Object
,别名 Merge
,代理命令(查看帮助):
$configuration | Merge $customization -on path, item
path item value type
---- ---- ----- ----
some/path item1 value1 ALL
some/path item2 value3 ALL
other/path item1 value2 SOME
other/path item1 value3 ALL
new/path item3 value3 SOME
new/path item3 value4 ALL
我有一个 configuration.csv
包含这样的模板数据:
| path | item | value | type |
|------------|-------|--------|------|
| some/path | item1 | value1 | ALL |
| some/path | item2 | UPDATE | ALL |
| other/path | item1 | value2 | SOME |
和 customization.csv
具有特定于服务的配置:
| path | item | value | type |
|------------|-------|--------|------|
| some/path | item2 | value3 | ALL |
| new/path | item3 | value3 | SOME |
我的目标是合并它们并最终得到这样的结果:
| path | item | value | type |
|------------|-------|--------|------|
| some/path | item1 | value1 | ALL |
| some/path | item2 | value3 | ALL |
| other/path | item1 | value2 | SOME |
| new/path | item3 | value3 | SOME |
这应该添加任何新条目并更新任何现有条目。没有一列可以用于唯一标识 - path
和 item
都需要合并,因为它们保证是唯一的。
经过大量搜索,我认为无需重新创建管理框架即可操作条目的最简单方法是通过 hashtable。在此过程中,我不得不考虑两种极端情况:
- 值中的附加逗号
- 空值
我得到的最终解决方案是这样的:
$configuration = Import-Csv .\configuration.csv
$customization = Import-Csv .\customization.csv
$merged = New-Object System.Collections.ArrayList
$hashTable = @{}
#initializing the hashTable with the defaults
foreach ($entry in $configuration)
{
$hashTable[$entry.path + ',' + $entry.item] = $entry.value + ',' + $entry.type
}
#updating the hashTable with customization that add or overwrite existing entries
foreach ($entry in $customization)
{
$hashTable[$entry.path + ',' + $entry.item] = $entry.value + ',' + $entry.type
}
#the regex handles multiple commas and empty values.
#It returns an empty string before and after group so we start from 1
foreach ($key in $hashTable.keys)
{
$psobject = [PSCustomObject]@{
path = ($key -split '(.*),(.*)')[1]
item = ($key -split '(.*),(.*)')[2]
value = ($hashTable[$key] -split '(.*),(.*)')[1]
type = ($hashTable[$key] -split '(.*),(.*)')[2]
}
[void] $merged.Add($psobject)
}
Write-Output $merged
导入后,我将 configuration.csv
转换为哈希表,其键由 path
和 value
组成。然后,我使用相同的哈希表对 customization.csv
执行相同的操作,该哈希表会覆盖任何现有的 key
值或将它们添加为新值。
第三个循环将 hashTable 转换为 PSCustomObject
,类似于 Import-Csv
所做的。我拆分了每个 key
和 value
属性,同时考虑了多个逗号和空值。
注意:正则表达式将在最后一次出现分隔符时拆分(这里是逗号,但你可以 select 任何东西,真的)。如果要在第一个拆分,可以使用(.*?),(.*)
。在我的例子中,只有 value
列可以包含分隔符的实例。
如果 CSV 文件有唯一列,则可以使用类似于
另一种方法是将键设置为所有列的总和,这将过滤掉 CSV 中的所有重复项,但拆分可能会变得棘手,具体取决于列中的值。
我建议使用 Compare-Object
,因为来自 customization.csv
的值应持续使用此文件值作为 -ReferenceObject
## Q:\Test19\SO_54948111.ps1
$conf = Import-Csv '.\configuration.csv'
$cust = Import-Csv '.\customization.csv'
$NewData = Compare-Object -ref $cust -diff $conf -Property path,item -PassThru -IncludeEqual|
Select-Object -Property * -ExcludeProperty SideIndicator
$NewData
$NewData |Export-Csv '.\NewData.csv' -NoTypeInformation
示例输出
> Q:\Test19\SO_54948111.ps1
path item value type
---- ---- ----- ----
some/path item2 value3 ALL
some/path item1 value1 ALL
other/path item1 value2 SOME
new/path item3 value3 SOME
您的想法“使用相同的哈希表来覆盖任何现有的键值或将它们添加为新的。”只有在 path, item
在每一侧都是唯一的情况下才有效因为您还将覆盖所有重复项...
考虑这个 Join-Object
cmdlet。
$configuration =
ConvertFrom-SourceTable
'
| path | item | value | type |
|------------|-------|--------|------|
| some/path | item1 | value1 | ALL |
| some/path | item2 | UPDATE | ALL |
| other/path | item1 | value2 | SOME |
| other/path | item1 | value3 | ALL |
'
$customization=
ConvertFrom-SourceTable
'
| path | item | value | type |
|------------|-------|--------|------|
| some/path | item2 | value3 | ALL |
| new/path | item3 | value3 | SOME |
| new/path | item3 | value4 | ALL |
'
使用 Merge-Object
,别名 Merge
,代理命令(查看帮助):
$configuration | Merge $customization -on path, item
path item value type
---- ---- ----- ----
some/path item1 value1 ALL
some/path item2 value3 ALL
other/path item1 value2 SOME
other/path item1 value3 ALL
new/path item3 value3 SOME
new/path item3 value4 ALL