#powershell #csv
#powershell #csv-файл
Вопрос:
У меня есть следующие данные в формате CSV:
KEY,VARNAME1,VARNAME2,VARNAME3
**1**,10,20,30
**1**,9,18,25
**1**,8,10,0
**2**,40,80,90
**2**,35,70,80
**2**,5,0,0
Я хочу прочитать данные из этого CSV-файла и написать новый CSV-файл, который выглядит следующим образом:
**1**,**2**
10,40
9,35
8,5
20,80
18,70
10,0
30,90
25,80
0,0
Другими словами: «КЛЮЧ» для каждой строки — это новый заголовок в новом csv. Значения переменных VARNAME1, VARNAME2 и т.д. объединяются в один столбец для каждого «КЛЮЧА».
Данные очень, очень большие. Он составляет до 50 ГБ (один файл). Вот почему я не пишу макрос или что-то еще, что я использую.
Я немного борюсь с sytax powershell.
Я читаю csv без проблем. Но тогда я не уверен, как написать правильный цикл FOR.
Или мне нужно настроить хэш-таблицу, также имея в виду огромный объем данных?
Комментарии:
1. О каком количестве «ключей» мы говорим для каждого файла? «Простой» способ повторного моделирования данных в желаемый формат вывода потребует одновременного хранения всех данных в памяти, но это может быть нежелательно, учитывая размер файла
2. @MathiasR.Jessen: Количество ключей также может быть очень большим ~ 1 млн. Я согласен, что основной проблемой является количество данных, которые необходимо сохранить в памяти. Я надеялся, что есть эффективный способ сделать это, не загружая все в память сразу.
Ответ №1:
Я почти не решаюсь опубликовать это, потому что оно определенно не будет масштабироваться до файла объемом 50 ГБ, но оно дает вам базовый алгоритм для перебора ваших данных для получения желаемого результата, который вы можете использовать в качестве отправной точки…
$csv = @"
KEY,VARNAME1,VARNAME2,VARNAME3
1,10,20,30
1,9,18,25
1,8,10,0
2,40,80,90
2,35,70,80
2,5,0,0
"@
$data = $csv | ConvertFrom-Csv;
# get the property names from the data
# i.e. VARNAME1, VARNAME2, VARNAME3
$propertyNames = $data[0].psobject.Properties.Name | where-object { $_ -ne "KEY" }
# group by key so we can pair up the Nth row from each key group together.
# note - this won't scale very well :-(
$groups = $data | group-object "KEY"
# basically, transpose the data so that the VARNAME1 values from the
# first "KEY=1" record and the first "KEY=2" record are paired together,
# then the VARNAME1 values from the second "KEY=1" record and the second
# "KEY=2", etc, until we've processed all the records for VARNAME1, then
# start again with the VARNAME2 property, then VARNAME3. assumes there's
# the same number of "KEY=1" and "KEY=2" records
$rows = @()
foreach( $propertyName in $propertyNames )
{
for( $i = 0; $i -lt $groups[0].Count; $i )
{
$row = [ordered] @{};
foreach( $group in $groups )
{
$row.Add($group.Name, $group.Group[$i].$propertyName)
}
# = is exponentially expensive for very big dataset
$rows = new-object PSCustomObject -Property $row
}
}
$csv = $rows | ConvertTo-Csv
# note - strings instead of ints
$csv
# "1","2"
# "10","40"
# "9","35"
# "8","5"
# "20","80"
# "18","70"
# "10","0"
# "30","90"
# "25","80"
# "0","0"