Объединение двух файлов CSV при добавлении новых и перезаписи существующих записей - PullRequest
0 голосов
/ 01 марта 2019

У меня есть 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, поскольку они гарантированно являются уникальными.

Ответы [ 3 ]

0 голосов
/ 01 марта 2019

Я предлагаю использовать Compare-Object, и в качестве значений из customization.csv следует сохранять значения этих файлов как -ReferenceObject

## Q:\Test\2019\03\01\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:\Test\2019\03\01\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
0 голосов
/ 01 марта 2019

Ваша идея ', использующая ту же самую hashTable, которая перезаписывает любые существующие значения ключа или добавляет их как новые. ' будет работать только в том случае, если path, item уникально на каждой стороне, так как вы также перезаписываете любые дубликаты... Учтите это Join-Object командлет.

$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
0 голосов
/ 01 марта 2019

После долгих поисков я подумал, что самый простой способ манипулировать записями без воссоздания управляющей инфраструктуры - через .В ходе процесса мне пришлось учесть два крайних случая:

  1. дополнительные запятые в значениях
  2. пустые значения

Окончательное решение, которое я получил, это:

$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, используя ту же самую hashTable, которая перезаписывает любые существующие значения key или добавляет их как новые.

Третий цикл преобразует hashTable в PSCustomObject, аналогично тому, что делает Import-Csv,Я разделяю каждый из атрибутов key и value при учете нескольких запятых, а также пустых значений.
ПРИМЕЧАНИЕ : регулярное выражение будет разделено на последнее вхождение разделителя (здесь это запятая,но вы можете выбрать что угодно, правда).Если вы хотите разделить на первое, вы можете использовать (.*?),(.*).В моем случае только столбец value может содержать экземпляр разделителя.

Если CSV имеет уникальный столбец, то можно использовать решение, подобное , этот ответ .

Другой альтернативой является установка ключей равными сумме всех столбцов, и это отфильтровывает любые дубликаты в CSV, но разбиение может стать сложным, в зависимости от значений в столбцах.

...