Экспорт данных в том порядке, в котором они были добавлены — PowerShell Export-Csv

у меня есть этот код

function get-data()
{
   $rec=[PSCustomObject]@()
   $DLGP = "" | Select "Name","Grade","Score"

   foreach($record in $data) 
   {
       $DLGP.Name=$record.name
       $DLGP.Grade=$record.grade
       $DLGP.Score=$record.score
       $rec += $DLGP
   }
   return $rec
}

$mydata=get-data
$mydata | Export-Csv -Path $outputPath -NoTypeInformation

Проблема в том, что данные не экспортируются в том порядке, в котором я добавил их в $rec

Как я могу экспортировать его в том порядке, в котором он был добавлен?


person John Casablanca    schedule 30.06.2018    source источник
comment
По умолчанию [PSCustomObject] не упорядочен. Начиная с Powerschell версии 4 или 5, я думаю, есть упорядоченные пользовательские объекты. Просто добавьте [ordered] перед [PSCutomObject] .... вот так: [ordered][PSCostomObject]   -  person Olaf    schedule 30.06.2018
comment
@Olaf: экземпляр [pscustomobject] всегда перечислял свои свойства в порядке определения. Это хэш-таблицы, записи которых перечисляются в произвольном порядке; В PSv3 введено [ordered] @{ ... }, позволяющее определять упорядоченные литералы хеш-таблиц, записи которых также перечисляются в порядке определения, а также разрешено преобразование литералов хеш-таблиц в [pscustomobject], и в этом случае [ordered] подразумевается — в PSv2 такие приведения просто не работали. вообще (были бездействующие). Однако проблема OP не связана с порядком участников - см. Мой ответ. [ordered] работает только до @{ ... }.   -  person mklement0    schedule 01.07.2018


Ответы (2)


Даже не используя вашу функцию, простой

$mydata = $data | select Name,Grade,Score

дало бы желаемый результат.

Ваша функция ИМО слишком сложна:

$Data = @"
Name,Grade,Score,Dummy
Anthoni,A,10,v
Brandon,B,20,x
Christian,C,30,y
David,D,40,z
"@ | ConvertFrom-Csv

function get-data() {
   ForEach($record in $data) {
       [PSCustomObject]@{
           Name =$record.name
           Grade=$record.grade
           Score=$record.score
       }
   }
}

$mydata=get-data
$mydata # | Export-Csv -Path $outputPath -NoTypeInformation

Возвращает здесь тот же порядок:

Name      Grade Score
----      ----- -----
Anthoni   A     10
Brandon   B     20
Christian C     30
David     D     40
person Community    schedule 30.06.2018

Полезный ответ LotPings предлагает эффективные решения.

Что касается что вы пробовали:

Создав только один [pscustomobject] экземпляр вне цикла:

$DLGP = "" | Select "Name","Grade","Score"

а затем только обновлять свойства этого экземпляра в каждой итерации цикла:

$DLGP.Name=$record.name
# ....

вы эффективно добавили один и тот же экземпляр [pscustomobject] несколько раз в результирующий массив вместо того, чтобы создавать отдельный объект в каждой итерации.

Поскольку один и тот же объект неоднократно обновлялся, этот объект получил свойства последнего объекта во входной коллекции, $data.

Как в сторону:

[PSCustomObject] @() фактически такой же, как @(): [PSCustomObject] игнорируется, и вы получаете массив [object[]].

Чтобы ввести массив как массив, содержащий [PSCustomObject] экземпляров, вам нужно будет использовать приведение типа массив: [PSCustomObject[]] @().

Однако, учитывая, что экземпляры любого типа могут быть приведены к [PSCustomObject], что на самом деле то же самое, что и [psobject], это не дает ни безопасности типов, ни выигрыша в производительности.

Кроме того, поскольку ваша переменная $rec не имеет ограничений по типу (она определяется как $rec = [<type>] ..., а не [<type>] $rec = ...), и вы используете += для "добавления" в массив (что неизменно требует создания нового экземпляра за кулисами), $rec вернется к массиву [object[]] после первой операции +=.

person mklement0    schedule 01.07.2018