PowerShell - расширение столбца массива в массиве с повторяющимися строками - PullRequest
1 голос
/ 08 ноября 2019

У меня есть System.Array объект с именем $Data, первый ([0]) элемент выглядит так:

RecordDate              : {43739, 43740, 43741, 43742...}
MAX_LAST_UPDATE_DATE    : 30/10/2019 14:08:33
EMPLOYEE_NUMBER         : 1000522
EFFECTIVE_START_DATE    : 01/10/2019 00:00:00
EFFECTIVE_END_DATE      : 31/12/4712 00:00:00
CC                      : 0726
REGION_NAME             : Head Office
LOCATION_NAME           : Inventory
FIRST_NAME              : Name
MIDDLE_NAMES            : Mid
LAST_NAME               : Last
KNOWN_AS                : NickName
JOB_TITLE               : Inventory Manager
WORK_NUMBER             : 
Employment Category     : Full Time
NORMAL_HOURS            : 40
GROUP_NAME              : Indirect
Manager Employee Number : 1034422
PERSON_TYPE             : Employee
HIRE_DATE               : 16/11/1983 00:00:00
TERMINATION_DATE        : 
DATE_OF_BIRTH           : 23/05/1966 00:00:00
NATIONAL_IDENTIFIER     : 111

Я пытаюсь как-то разворачивать первый столбец "RecordDate" на весь массив , например:

RecordDate              : 43739
MAX_LAST_UPDATE_DATE    : 30/10/2019 14:08:33
EMPLOYEE_NUMBER         : 1000522
EFFECTIVE_START_DATE    : 01/10/2019 00:00:00
EFFECTIVE_END_DATE      : 31/12/4712 00:00:00
CC                      : 0726
REGION_NAME             : Head Office
LOCATION_NAME           : Inventory
FIRST_NAME              : Name
MIDDLE_NAMES            : Mid
LAST_NAME               : Last
KNOWN_AS                : NickName
JOB_TITLE               : Inventory Manager
WORK_NUMBER             : 
Employment Category     : Full Time
NORMAL_HOURS            : 40
GROUP_NAME              : Indirect
Manager Employee Number : 1034422
PERSON_TYPE             : Employee
HIRE_DATE               : 16/11/1983 00:00:00
TERMINATION_DATE        : 
DATE_OF_BIRTH           : 23/05/1966 00:00:00
NATIONAL_IDENTIFIER     : 111

RecordDate              : 43740
MAX_LAST_UPDATE_DATE    : 30/10/2019 14:08:33
EMPLOYEE_NUMBER         : 1000522
EFFECTIVE_START_DATE    : 01/10/2019 00:00:00
EFFECTIVE_END_DATE      : 31/12/4712 00:00:00
CC                      : 0726
REGION_NAME             : Head Office
LOCATION_NAME           : Inventory
FIRST_NAME              : Name
MIDDLE_NAMES            : Mid
LAST_NAME               : Last
KNOWN_AS                : NickName
JOB_TITLE               : Inventory Manager
WORK_NUMBER             : 
Employment Category     : Full Time
NORMAL_HOURS            : 40
GROUP_NAME              : Indirect
Manager Employee Number : 1034422
PERSON_TYPE             : Employee
HIRE_DATE               : 16/11/1983 00:00:00
TERMINATION_DATE        : 
DATE_OF_BIRTH           : 23/05/1966 00:00:00
NATIONAL_IDENTIFIER     : 111

RecordDate              : 43741
MAX_LAST_UPDATE_DATE    : 30/10/2019 14:08:33
...

Есть ли способ сделать это с каким-нибудь подлым Select -expandproperty или сделать противоположное тому, на что способен Group-Object;без сочетания циклов for($i) и for($j)?

Это довольно просто для таблицы в Excel PowerQuery, так как вы просто нажимаете Развернуть и вуаля.

С уважением, Ярек

1 Ответ

1 голос
/ 08 ноября 2019

Вы можете объединить Select-Object -ExpandProperty с общим параметром -PipelineVariable и клонированием (синтаксис PSv3 +):

Для входных коллекций экземпляров [pscustomobject] или [hashtable]:

# Sample input array of custom objects to expand by .RecordDate
$array =
  [pscustomobject] @{ RecordDate = 1, 2; OtherProp1 = 'one'; OtherProp2 = 'two' },
  [pscustomobject] @{ RecordDate = 3, 4; OtherProp1 = 'three'; OtherProp2 = 'four' }

# Write the array elements to the pipeline, and store each in variable
# $objectOrHashtable for use in a later pipeline segment.
Write-Output $array -PipelineVariable objectOrHashtable |
  # Expand the input object's .RecordData property, i.e. send its
  # elements one by one to the next pipeline segment.
  Select-Object -ExpandProperty RecordDate | 
    ForEach-Object {
      # Clone the original input object.
      $clone = if ($objectOrHashtable -is [Management.Automation.PSCustomObject]) {
        $objectOrHashtable.psobject.Copy()
      } else { # assume [hashtable] or a type that implements [System.ICloneable]
        $objectOrHashtable.Clone()
      }
      # Assign the record date at hand to the clone...
      $clone.RecordDate = $_
      # ... and output it.
      $clone
    }

Вышесказанное дает следующее;обратите внимание, что было выведено 4 объекта на основе перечисления элементов массива .RecordDate входных объектов при сохранении всех других свойств:

RecordDate OtherProp1 OtherProp2
---------- ---------- ----------
         1 one        two
         2 one        two
         3 three      four
         4 three      four

Примечание:

  • Вышеприведенное работает с двумя типами входных объектов:

    • пользовательских объектов ([pscustomobject] экземпляров, таких как созданные Import-Csv)

      • Примечание: по техническим причинам вы не можете использовать -is [pscustomobject] и вместо этого должны использовать полное имя типа System.Management.Automation.PSCustomObject (префикс System. может быть опущен);[pscustomobject] по историческим причинам совпадает с [psobject] (System.Management.Automation.PSObject), а -is [psobject] также верно для объектов, которые не являются пользовательскими объектами.
    • хеш-таблицы (System.Collections.Hashtable экземпляров - но не [ordered] хеш-таблицы);в более общем смысле, любой тип, который реализует System.ICloneable.

  • Клонирование, которое выполняется на пользовательских объектах и ​​хэш-таблице, составляет shallow (member-мудро), но со скалярными строковыми и числовыми значениями, которые являются достаточными.

    • Как правило, интерфейс ICloneable не предписывает особенности поведения клонирования, поэтому его использование обычно не рекомендуется.

Для входных коллекций [System.Data.DataRow] экземпляров:

Клонирование коллекции System.Data.DataRow экземпляров - строк таблицы данных, System.Data.DataTable - требуется пользовательская логика клонирования , но подход и структура выходных данных в основном одинаковы:

# Create a sample DataTable...
$dt = [System.Data.DataTable]::new('sample')
# ... define the columns ...
$dt.Columns.AddRange([System.Data.DataColumn[]] (
  @{ ColumnName = 'RecordDate'; DataType = [object[]] },
  @{ ColumnName = 'OtherProp1'; DataType = [string] },
  @{ ColumnName = 'OtherProp2'; DataType = [string] }
))
# ...and add sample rows.
@{ RecordDate = 1, 2; OtherProp1 = 'one'; OtherProp2 = 'two' },
@{ RecordDate = 3, 4; OtherProp1 = 'three'; OtherProp2 = 'four' } | % {
  $dt.Rows.Add(($dr = $dt.NewRow()))
  foreach ($entry in $_.GetEnumerator()) {
    $dr[$entry.Key] = $entry.Value 
  }  
}

# Create an auxiliary, empty clone of the input data table
# to facilitate cloning of individual rows.
$dtAux = $dt.Clone()

# Write the data rows to the pipeline, and store each in variable
# $obj for use in a later pipeline segment.
Write-Output $dt.Rows -PipelineVariable row |
  # Expand the input object's .RecordData property, i.e. send its
  # elements one by one to the next pipeline segment.
  Select-Object -ExpandProperty RecordDate |
    ForEach-Object {
      # Clone the data row at hand.
      $dtAux.Clear(); $dtAux.ImportRow($row)
      $clone = $dtAux.Rows[0]
      # Assign the record date at hand to the clone...
      $clone.RecordDate = @($_)
      # ... and output it.
      $clone
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...