Войти

Показать полную графическую версию : Вывод элементов списка в виде массива


Страниц : [1] 2

NickM
25-10-2023, 19:24
Уважаемые, здравствуйте!

Задалcя вопросом обработки *.xml файлов, вроде бы даже добился какого-никакого решения поставленной перед Собою задачи, но вот одного не могу разрешить: вывод элемента списка в виде массива, Powershell его "подрезает" и отображает только несколько первых символов.

Список объявляю так:
$list2 = New-Object System.Collections.Generic.List[System.Object];
Наполняю так:
$aSumItog = @(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
foreach ($item in $tmplist2) {
$list2.Add([PSCustomObject]@{cFIO = $item; cSum = $aSumItog})
}


При выводе в консоль или в файл вижу следуюущее:
cFIO cSum
---- ----
Петров Петр Петрович {0, 0, 0, 0...}


, а хотелось бы видеть все столбцы массива.

Может, кто подскажет как этого добиться?

Sham
26-10-2023, 01:08
... | Format-Table 'cFIO', @{ Label='cSum'; Expression={ $_.cSum -join ', ' } }

Serguei Kouzmine
26-10-2023, 04:44
еще есть вариант перестать рассчитывать на нативные типы повершелла и просто как JSON выводить данные

$list2 | convertto-json -depth 10
...


{
"cFIO": "Петров Петр Петрович",
"cSum": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]
}
]

NickM
26-10-2023, 06:23
и просто как JSON выводить данные »
Ага, сгодится для дальнейшего парсинга, но Мне надо было в табличный вид, для человеческого восприятия;

... | Format-Table 'cFIO', @{ Label='cSum'; Expression={ $_.cSum -join ', ' } } »

Спасибо, попробую прикрутить.

Вчера уже выкрутился созданием нового списка и впихиванием в него элементов массива, да, топорно получилось.

DJ Mogarych
26-10-2023, 10:13
$aSumItog -join "`n"

YuS_2
26-10-2023, 13:30
выкрутился созданием нового списка и впихиванием в него элементов массива »
массив приводим к строке (вариантов мульён) и впихиваем невпихуемое в столбец...
один из вариантов:
[string]$aSumItog

NickM
26-10-2023, 14:09
один из вариантов: »
Благодарю за участие!

Поставленный вопрос решил, но очень мало опыта работы с powershell, практически нулевой.

Но, желаемого достиг, правда с излишним быдлокодом, да (стесняюсь полностью код выложить, там полный атас).

Поделюсь, может гуру, при желании, подскажут, как это упростить?


Пару блоков, которые Мне кажутся излишними, но не знаю как их упростить:


1.
В этом пункте требуется получить список $list1 с уникальными текстовыми значениями и инициализированным массивом чисел.

Наполняю два списка данными из *.xml, $tmplist1 используется как временный, для сортировки. В $list1 и $list3 производится работа с массивом числовых значений:
#Основные массивы-списки для всех требуемых значений
$list1 = New-Object System.Collections.Generic.List[System.Object];
$list3 = New-Object System.Collections.Generic.List[System.Object];
...
$list3.Add([PSCustomObject]@{cPeriod = $cPeriod; cFIO = $cFIO; cINN = $cINN; cSNILS = $cSNILS; cmes = $cMes; cSum = $cSum});
...

#Подготовим временный массив - выполним сортировку и уберём дубли сотрудников
$tmplist1 = New-Object System.Collections.Generic.List[System.Object];
$tmplist1 = $list3 | Select-Object cFIO, cINN, cSNILS | Sort-Object cFIO, cINN, cSNILS | Get-Unique -AsString

#Инициализируем список c перс.данными и пустым массивом для сумм
$aSumItog = @(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
foreach ($item in $tmplist1) {
$list1.Add([PSCustomObject]@{cFIO = $item.cFIO; cINN = $item.cINN; cSNILS = $item.cSNILS; cSum = $aSumItog})
}


2.
Как итог выполнения всего кода, наполненный рабочий список $list1 требуется вывести в *.csv с разделителем [char]9, т.е. сформировать табличную часть.

Реализовал, опять же, с использованием дополнительного списка, где наполняю этот список:
$tmplist3 = [System.Collections.Generic.List[string]]::new()
foreach ($item in $list1) {
$tmplist3.Add($item.cFIO + [char]9 + $item.cINN + [char]9 + $item.cSNILS + [char]9 + ($item.cSum -join "`t"))
}
, а после сохраняю:
$tmplist3 | Out-File 'КНД_1151111.csv'

YuS_2
27-10-2023, 09:45
Пару блоков, которые Мне кажутся излишними, но не знаю как их упростить »
Задача очень похожа на ситуацию с проблемой XY (https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%BE%D0%B1%D0%BB%D0%B5%D0%BC%D0%B0_XY_(%D0%9E%D1%88%D0%B8%D0%B1%D0%BA%D0%B0_%D0%BC%D0% BE%D0%BB%D0%BE%D1%82%D0%BA%D0%B0))

Наполняю два списка данными из *.xml »
Здесь, для решения вопроса, просто необходимо увидеть задачу в целом.
Т.е. нужен пример файла (а лучше файлов) с исходными данными (конфиденциальную инфу можно заменить какими-нибудь фейками) и желаемый результат, т.е. то, что необходимо получить из исходных данных. Промежуточные "просмотры" данных в консоли, не имеют смысла обычно, но если сильно желание, то тоже надо бы указать в каком виде хочется их просматривать.

NickM
27-10-2023, 11:28
Задача очень похожа на ситуацию с проблемой XY »
Не, задача предельная ясна и понятна - произвести сверку двух отчётных форм, которые в *.xml формате и развернуть их в табличный вид и сохранить в *.csv для возможности дальнейших манипуляций в табличном редакторе;

Сверка заключается в том, что бы проверить соответствие всех перс.данных по физ.лицам отражённых в трёх месячных формах 1151162 с квартальной формой 1151111.
Для этого, эти перс.данные из *.xml файлов извлекаются, помещаются в списки, а списки уже построчно сравниваются;

Т.е. нужен пример файла (а лучше файлов) с исходными данными (конфиденциальную инфу можно заменить какими-нибудь фейками) и желаемый результат »
Файлы найти не проблема, это электронный вариант отчётных форм налоговых деклараций КНД 1151111 и КНД 1151162.

Заменил и приложил;

Промежуточные "просмотры" данных в консоли, не имеют смысла обычно, но если сильно желание, то тоже надо бы указать в каком виде хочется их просматривать. »
Зачастую, в консоли, просматриваю/ отлаживаю вывод, из-за отсутствия знаний, т.к. сказать "негорячую" просматриваю результаты выполнения той или иной процедуры/ функции.

YuS_2
27-10-2023, 14:43
помещаются в списки, а списки уже построчно сравниваются »
Файлы найти не проблема, это электронный вариант отчётных форм налоговых деклараций КНД 1151111 и КНД 1151162.
Заменил и приложил»
так, вот уже проще... только, что должно получиться из этих файлов на выходе? Т.е. конечный результат (файл) как должен выглядеть? Для полного понимания его тоже надо бы сделать вручную...
И да, судя по файлам, количество элементов (и атрибутов элементов тоже) в них различное... а могут быть ещё какие-нибудь поля, которых нет в примерах? Если парсить xml, то нужны будут наименования элементов, по которым необходимо делать выборку... или там просто всё подряд, что найдем, то и "выплюнуть" на выход?

NickM
27-10-2023, 15:24
И да, судя по файлам, количество элементов (и атрибутов элементов тоже) в них различное... а могут быть ещё какие-нибудь поля, которых нет в примерах? Если парсить xml, то нужны будут наименования элементов, по которым необходимо делать выборку... или там просто всё подряд, что найдем, то и "выплюнуть" на выход? »
Можно вместо ответа прикреплю сценарий? Это не будет выглядеть наглостью?

UPD: Перезалил файл по причине добавления комментариев к сценарию.

Pavel Nagaev
27-10-2023, 15:25
Придирки по коду :-).

$list1 = New-Object System.Collections.Generic.List[System.Object];
$list3 = New-Object System.Collections.Generic.List[System.Object];

Можно на это поменять

using namespace System.Collections.Generic
$list1 = [List[string]]@()
$list3 = [List[string]]@()


Табуляцию [char]9 на "`t"

Причём вы тут
$tmplist3.Add($item.cFIO + [char]9 + $item.cINN + [char]9 + $item.cSNILS + [char]9 + ($item.cSum -join "`t")

используте "`t", но зачем-то и [char]9


вот это
$list3.Add([PSCustomObject]@{cPeriod = $cPeriod; cFIO = $cFIO; cINN = $cINN; cSNILS = $cSNILS; cmes = $cMes; cSum = $cSum});

на это и в конце строки ; не нужна.

$list3.Add([PSCustomObject]@{cPeriod = $cPeriod;
cFIO = $cFIO;
cINN = $cINN;
cSNILS = $cSNILS;
cmes = $cMes;
cSum = $cSum;
}
)
Это чисто удобство чтения.

Кодировку добавить.

$tmplist3 | Out-File 'КНД_1151111.csv' -Encoding utf8

NickM
27-10-2023, 15:32
Придирки по коду :-). »
Благодарю, приму к сведению;

используете "`t", но зачем-то и [char]9 »
Только учусь :sorry:

Кодировку добавить. »
Ага, сейчас сохраняет в "UTF16-LE", но в том же "Excel" кириллица отображается корректно.

YuS_2
27-10-2023, 18:43
Можно вместо ответа прикреплю сценарий? Это не будет выглядеть наглостью? »
Да ноу проблемс, но так будет дольше и результат - не факт, что получится то, что требуется. Лучше было бы увидеть результат, который нужен... ну, или алгоритм, что куда и зачем.

NickM
27-10-2023, 18:45
ну, или алгоритм, что куда и зачем. »
UPD: Перезалил файл по причине добавления комментариев к сценарию. »
Прокомментировал каждый блок кода.

YuS_2
28-10-2023, 18:18
Прокомментировал каждый блок кода. »
если бы эти комментарии могли помочь...
В общем, я предупреждал, что без алгоритма действий, результат может выйти совсем не таким, каким ожидался... :)
script.ps1 (кодировку скрипта лучше выбрать UTF8)
function Get-NodeAttrDoc ($xml,$node,$enc){
process{
$n = $xml.selectnodes("//$node")
[pscustomobject]@{
'КНД' = $n.кнд
'Период' = $n.период
}
}
}

function Get-NodeDataOut ($xml,$node,$per,$dat,$fio,$enc,$knd){
process{
$t = $xml.selectnodes("//$node")
$f = $t.$fio
$s = @(@(0)*13)
if (($i=[int]$per) -lt 13){$s[$i] = [int]$t.сумвыпл} else {
$sv = [int[]]$xml.selectnodes("//$dat").сумвыпл
switch ($per){
$kv[0]{$s[1]=$sv[0];$s[2]=$sv[1];$s[3]=$sv[2]}
$kv[1]{$s[4]=$sv[0];$s[5]=$sv[1];$s[6]=$sv[2]}
$kv[2]{$s[7]=$sv[0];$s[8]=$sv[1];$s[9]=$sv[2]}
$kv[3]{$s[10]=$sv[0];$s[11]=$sv[1];$s[12]=$sv[2]}
}
$s[0] = ($s|measure -sum).sum
}
[pscustomobject]@{
'КНД' = $knd
'ФИО' = ($f.фамилия,$f.имя,$f.отчество) -join ' '
'ИННФЛ' = $t.иннфл
'СНИЛС' = $t.снилс
'СумГод' = [int]$s[0]
'01' = $s[1]
'02' = $s[2]
'03' = $s[3]
'04' = $s[4]
'05' = $s[5]
'06' = $s[6]
'07' = $s[7]
'08' = $s[8]
'09' = $s[9]
'10' = $s[10]
'11' = $s[11]
'12' = $s[12]
}
}
}

function get-sumdoc1162 ($elem,$i){
$b = $i|%{($elem.$_|measure -sum).sum}
[pscustomobject]@{
'КНД' = $elem.кнд[0]
'ФИО' = $elem.фио[0]
'ИННФЛ' = $elem.иннфл[0]
'СНИЛС' = $elem.снилс[0]
'СумГод' = [int]($b|measure -sum).sum
'01' = [int]$b[0]
'02' = [int]$b[1]
'03' = [int]$b[2]
'04' = [int]$b[3]
'05' = [int]$b[4]
'06' = [int]$b[5]
'07' = [int]$b[6]
'08' = [int]$b[7]
'09' = [int]$b[8]
'10' = [int]$b[9]
'11' = [int]$b[10]
'12' = [int]$b[11]
}
}

$path = $psscriptroot
if ($host.version.major -gt 5) {
$enc = 'windows-1251'
$csv = @{
Encoding = 'utf8'
NoTypeInformation = $true
QuoteFields = 'ФИО'
}
} else {
$enc = 'default'
$csv = @{
Encoding = 'utf8'
NoTypeInformation = $true
}
}
$flt = 'NO_*.xml'
$nd = 'Документ'
$nd_dfl = 'ДанФЛПолуч'
$nd_svmk = 'СвВыплМК'
$nd_psfl = 'ПерсСвФЛ'
$fio = 'ФИО'
$kv = @('21','31','33','34')
$arr1162_i, $arr1111 = @(),@()

dir $path -filt $flt -file|%{
$x = [xml](gc $_.fullname -enc $enc)
$tmp = get-nodeattrdoc $x $nd $enc
$knd = $tmp.кнд
$per = $tmp.период
if ($knd -eq '1151111'){
$arr1111 += get-nodedataout -xml $x -node $nd_dfl -per $per -d $nd_svmk -f $fio -enc $enc -knd $knd
} else {
$arr1162_i += get-nodedataout -xml $x -node $nd_psfl -per $per -f $fio -enc $enc -knd $knd
}
}
$m = 1.. 12|%{"$_".padleft(2,'0')}
$arr1162 = $arr1162_i|group -prop 'иннфл'|%{get-sumdoc1162 $_.group $m}
$arr1162|sort 'ФИО'|export-csv '1162.csv' @csv
$arr1111|sort 'ФИО'|export-csv '1111.csv' @csv

$arr1111+$arr1162|sort 'ФИО'|ft * -a -w

NickM
28-10-2023, 21:36
результат может выйти совсем не таким, каким ожидался... »
Результат вышел и в принципе по коду всё понятно - Вы вообще не использовали списки и обошлись только массивами, всё завернули в процедуры/ функции и передачами параметров в оные (одной функцией считали данные из двух разных форм), избавились от сравнения текстовых переменных, не учли копейки и возможное отсутствие некоторых тегов.

Круто!

YuS_2
28-10-2023, 22:26
Результат вышел »
Оно и понятно, что даже отсутствие результата - тоже результат... Вопрос только в том, выполняет код необходимую задачу или нет. :)

не использовали списки »
а зачем они здесь?

не учли копейки »
а их надо учитывать?

и возможное отсутствие некоторых тегов »
примеры, примеры и ещё раз примеры исходных данных... они всегда нужны для тестов.

NickM
28-10-2023, 22:49
а зачем они здесь? »
Не, задача предельная ясна и понятна - произвести сверку двух отчётных форм»
Сам использовал такой код:
#Выполним сверку между отчётами и результат сохраним в файл
$tmplist4 | ?{$tmplist3 -notcontains $_} | Out-File 'Отсутствуют_в_КНД_1151111.csv';
$tmplist3 | ?{$tmplist4 -notcontains $_} | Out-File 'Отсутствуют_в_КНД_1151162.csv';

а их надо учитывать? »
Ага, у Нас пока платят в рублях и с копейками:
СумВыпл="70000.00"

Цитата NickM:
и возможное отсутствие некоторых тегов » »
Сам проверял отсутствие тегов в сравнении с $null:
if ($item3.cMes -ne $null) {}
...
if ($aSum[$index] -eq $null) {}

примеры, примеры и ещё раз примеры исходных данных... они всегда нужны для тестов. »
Вот, добавил пару строк в тестовые файлы, на которых может всплыть ошибка преобразования типов данных.

YuS_2
29-10-2023, 12:23
Не, задача предельная ясна и понятна - произвести сверку двух отчётных форм» »
И всё равно, это не ответ на вопрос:
а зачем они здесь? »
Если задать его по-другому: а зачем именно списки? Т.е. вот это:
New-Object System.Collections.Generic.List[System.Object]
для чего? Чем обычные массивы не устроили?
А на счет сверки двух отчетных форм... что именно сверяется? Вы же не думаете, что скилл телепатии у меня настолько развит? :)
По Вашим примерам понятно, что есть два вида форм, одна из которых содержит данные за месяц, другая за квартал... так вот каким образом Вам необходимо их сверять? Помесячно, поквартально, за год, за пятилетку и т.д.
Т.е. технически сверку сделать - вообще, не проблема. Тут важно получить данные и получить их в том виде, который требуется...

Ага, у Нас пока платят в рублях и с копейками »
Вот видите, это пример того, что без внятного ТЗ, как правило и результат ХЗ :)
У нас, например, не в рублях и нет никаких копеек...

Далее...
Вот, добавил пару строк в тестовые файлы, на которых может всплыть ошибка преобразования типов данных. »
На основании имеющихся исходных файлов, предполагалось, что на отдельное физлицо приходится по отдельному же файлу (помесячно и поквартально)... видимо, ошибочное было предположение и естественно, парсер, построенный на неверных предположениях, будет и работать неверно... В общем-то, именно поэтому и требуется описание задачи и примеры наиболее различные между собой и желательно не на единственного человека, а на нескольких, чтобы учесть все нюансы. Ковырять же чужой код для восстановления алгоритма - не самый продуктивный вид программирования...

Мой код опирался, помимо основной, больше на вот эту задачу (собственно, в первом сообщении, это и было главным вопросом):
Мне надо было в табличный вид, для человеческого восприятия »

По коду парсера:
Основной скелет кода составлен, но для доведения этого кода "до ума", необходимо таки уточнение многих моментов, которые было бы неплохо описать в виде:
1. Вот исходные файлы, на одного-два-три-...-n физлиц.
2. Из них необходимо получать вот такие вот две формы (суммы ли в тех формах должны быть, либо только отдельные данные, сведенные по ИННФЛ или по какому-то ещё признаку, что-то ещё важное...).
3. В общем, сами эти итоговые формы, вернее их содержание, для сверки (опять же по нескольким физлицам), которые должны получиться из исходных данных, необходимо "нарисовать" вручную. А также требующийся формат конечных, выходных файлов, тоже было бы неплохо указать.
Так будет проще составить парсер, который будет делать то, что от него требуется.

По новым примерам было, конечно, проще поправить код... но непонятно, как могут возникать различия при сверке, т.к. Вашим кодом они не обнаружены. В том смысле, что вроде бы нужны ещё и четкие примеры таких различий в исходных данных, которые требуется обнаруживать сверкой.
Вот код, в котором можно легко сделать сверку по тем данным, которые Вы предоставили, но за один квартал. Не обращайте внимание, что нет выходных файлов сверки (это организовать несложно), смотрите в консоль, там можете визуально сравнивать данные, сгруппированные по ИННФЛ. В версии powershell 5.1 автоматическое преобразование типов сделает вывод целых чисел, без нулей после запятой (при желании можно сделать принудительную типизацию), а в версии PS 7.3.6, все числа будут выведены, как [double]
function Get-NodeAttrDoc ($xml,$node,$enc){
process{
$n = $xml.selectnodes("//$node")
[pscustomobject]@{
'КНД' = $n.кнд
'Период' = $n.период
}
}
}

function Get-NodeDataOut ($xml,$node,$per,$dat,$fio,$enc,$knd){
process{
$tarr = $xml.selectnodes("//$node")
$out = foreach($t in $tarr){
$f = $t.$fio
$s = @(@([double]0)*13)
if (($i=[int]$per) -lt 13){$s[$i] = [double]$t.сумвыпл} else {
$sv = [double[]]$xml.selectnodes("//$dat").сумвыпл
switch ($per){
$kv[0]{$s[1]=$sv[0];$s[2]=$sv[1];$s[3]=$sv[2]}
$kv[1]{$s[4]=$sv[0];$s[5]=$sv[1];$s[6]=$sv[2]}
$kv[2]{$s[7]=$sv[0];$s[8]=$sv[1];$s[9]=$sv[2]}
$kv[3]{$s[10]=$sv[0];$s[11]=$sv[1];$s[12]=$sv[2]}
}
$s[0] = ($s|measure -sum).sum
}
[pscustomobject]@{
'КНД' = $knd
'ФИО' = ($f.фамилия,$f.имя,$f.отчество) -join ' '
'ИННФЛ' = $t.иннфл
'СНИЛС' = $t.снилс
'СумГод' = $s[0]
'01' = $s[1]
'02' = $s[2]
'03' = $s[3]
'04' = $s[4]
'05' = $s[5]
'06' = $s[6]
'07' = $s[7]
'08' = $s[8]
'09' = $s[9]
'10' = $s[10]
'11' = $s[11]
'12' = $s[12]
}
}
}
end{return $out}
}

function get-sumdoc1162 ($elem,$i){
$b = $i|%{($elem.$_|measure -sum).sum}
[pscustomobject]@{
'КНД' = $elem.кнд[0]
'ФИО' = $elem.фио[0]
'ИННФЛ' = $elem.иннфл[0]
'СНИЛС' = $elem.снилс[0]
'СумГод' = ($b|measure -sum).sum
'01' = $b[0]
'02' = $b[1]
'03' = $b[2]
'04' = $b[3]
'05' = $b[4]
'06' = $b[5]
'07' = $b[6]
'08' = $b[7]
'09' = $b[8]
'10' = $b[9]
'11' = $b[10]
'12' = $b[11]
}
}

$path = "$psscriptroot\xml"
if ($host.version.major -gt 5) {
$enc = 'windows-1251'
$csv = @{
Encoding = 'utf8'
NoTypeInformation = $true
UseQuotes = 'AsNeed'
}
} else {
$enc = 'default'
$csv = @{
Encoding = 'utf8'
NoTypeInformation = $true
}
}
$flt = 'NO_*.xml'
$nd = 'Документ'
$nd_dfl = 'ДанФЛПолуч'
$nd_svmk = 'СвВыплМК'
$nd_psfl = 'ПерсСвФЛ'
$fio = 'ФИО'
$kv = @('21','31','33','34')
$arr1162_i, $arr1111 = @(),@()

dir $path -filt $flt -file|%{
$x = [xml](gc $_.fullname -enc $enc)
$tmp = get-nodeattrdoc $x $nd $enc
$knd = $tmp.кнд
$per = $tmp.период
$ndo = @{XML=$x;PER=$per;FIO=$fio;ENC=$enc;KND=$knd}
if ($knd -eq '1151111'){
$arr1111 += get-nodedataout @ndo -node $nd_dfl -d $nd_svmk
} else {
$arr1162_i += get-nodedataout @ndo -node $nd_psfl
}
}
$m = 1.. 12|%{"$_".padleft(2,'0')}
$arr1162 = $arr1162_i|group -prop 'иннфл'|%{get-sumdoc1162 $_.group $m}
$arr1162|sort 'ФИО'|export-csv '1162.csv' @csv
$arr1111|sort 'ФИО'|export-csv '1111.csv' @csv
$arr1111+$arr1162|sort 'ФИО'|ft * -a -w




© OSzone.net 2001-2012