У меня есть function
, он принимает object
, который имеет кучу properties
, и в конечном итоге создает новый объект из этого входного объекта. Я передаю ему dictionary
для сопоставления полей, чтобы сообщить функции, какой property
входной объект должен быть сопоставлен и переименован в какое имя свойства нового результирующего объекта. Так, например, входной объект может иметь двадцать свойств, но меня может интересовать только новый объект с пятью свойствами и новыми именами для этих свойств, поэтому таким образом у меня будет карта с пятью свойствами.
Моя функция работает, и вы также можете сделать ее лучше или эффективнее.
Но мой главный вопрос заключается в том, почему порядок свойств в результате не совпадает с порядком ключей моего словаря карты полей.
Вот код и данные для его воссоздания:
function Convert-APIObjectToCustomObject {
param (
[Array]$dataFromAPI,
[Hashtable]$fieldMap
)
$resultData = @()
foreach ($item in $dataFromAPI) {
$newObject = New-Object -TypeName PSCustomObject
foreach ($key in $fieldMap.Keys) {
$matchedProperty = $item.PSObject.Properties | Where-Object { $_.Name.ToLower() -eq $fieldMap[$key].ToLower() }
if ($matchedProperty) {
$propertyValue = $matchedProperty.Value
} else {
Write-Warning "Property '$($fieldMap[$key])' not found on the input object. Setting default value."
$propertyValue = $null # or you can set it to '' for an empty string
}
$newObject | Add-Member -MemberType NoteProperty -Name $key -Value $propertyValue
}
$resultData += $newObject
}
return $resultData
}
# Example usage:
$dataFromAPI = @(
[PSCustomObject]@{ InstrumentId='1'; ServiceLayer='Service1'; MaturityDate=1; Gheimat='5' ; ExtraCol = '45' },
[PSCustomObject]@{ InstrumentId='2'; ServiceLayer='Service2'; MaturityDate=2; Gheimat='17'; ExtraCol = '1000'},
[PSCustomObject]@{ InstrumentId='3'; ServiceLayer='Service1'; MaturityDate=1; Gheimat='3' ; ExtraCol = 'Hi'},
[PSCustomObject]@{ InstrumentId='4'; ServiceLayer='Service1'; MaturityDate=1; Gheimat='7' ; ExtraCol = 'Hello' }
)
$fieldsMap = @{
"Id" = "InstrumentId"
"Service" = "ServiceLayer"
"Propertyx" = "MaturityDate"
"Price" = "Gheimat"
}
$resultData2 = Convert-APIObjectToCustomObject -dataFromAPI $dataFromAPI -fieldMap $fieldsMap
поэтому я хочу, чтобы порядок свойств, отображаемых в моем результате, был таким же, как порядок "keys"
, который я определил в своем fieldMap
. Но в настоящее время это не так. Как мне это сделать?
Проблема с вашим кодом заключается в том, что переменная $fieldMap
представляет собой Hashtable
вместо OrderedDictionary. Следующая проблема — параметр -fieldMap
, набранный как Hashtable
вместо IDictionary
или OrderedDictionary
.
Что касается повышения эффективности вашего кода, вы можете использовать .PSObject.Properties , чтобы отразить свойства вашего $item
в цикле. Вы также можете, опять же, использовать OrderedDictionary
для создания нового объекта, а затем привести его к ускорителю типа [pscustomobject] . Это значительно повышает эффективность вашего кода, Add-Member
это очень медленно по сравнению с этим методом. Дополнительную информацию см. в разделе соображения-авторства-сценариев#использовать-упорядоченный-словарь-для-динамического-создания-новых-объектов.
Наконец, вы можете передавать объекты из своей функции без необходимости +=
в массив. Также очень неэффективно, см. соображения по созданию скриптов#добавление массива.
Подводя итог (используя тот же $dataFromAPI
, что и в вашем вопросе, для более короткого кода):
function Convert-APIObjectToCustomObject {
param (
[Array] $dataFromAPI,
[System.Collections.IDictionary] $fieldMap
)
foreach ($item in $dataFromAPI) {
$newObject = [ordered]@{}
$reflectedProperties = $item.PSObject.Properties
foreach ($key in $fieldMap.Keys) {
$matchedProperty = $reflectedProperties[$fieldMap[$key]]
if ($matchedProperty) {
$propertyValue = $matchedProperty.Value
}
else {
Write-Warning "Property '$($fieldMap[$key])' not found on the input object. Setting default value."
$propertyValue = $null # or you can set it to '' for an empty string
}
$newObject[$key] = $propertyValue
}
[pscustomobject] $newObject
}
}
$dataFromAPI = @(
# same as before
)
$fieldsMap = [ordered]@{
'Id' = 'InstrumentId'
'Service' = 'ServiceLayer'
'Propertyx' = 'MaturityDate'
'Price' = 'Gheimat'
}
Convert-APIObjectToCustomObject -dataFromAPI $dataFromAPI -fieldMap $fieldsMap
fieldMap
— это хеш-таблица в вашем текущем примере, порядок ключей в хеш-таблице не обеспечивается.