创建一个具有给定顺序的属性的新对象

问题描述 投票:0回答:1

我有一个

function
,它需要一个
object
,其中有一堆
properties
,最终它从该输入对象创建一个新对象。我将
field-mapping
dictionary 传递给它,告诉函数输入对象的哪些
property
应该映射 并重命名 到新结果对象的属性名称。因此,例如输入对象可以有二十个属性,但我可能只对具有五个属性的新对象和这些属性的新名称感兴趣,这样我将拥有一个包含五个属性的映射。 我的功能有效,也非常欢迎您使其变得更好或更高效。 但我的主要问题是为什么结果中属性的order与我的字段映射字典的键顺序不同。

这是重新创建它的代码和数据:

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

所以我希望结果中出现的属性的 order 与我在

"keys"
中定义的
fieldMap
的顺序相同。但目前情况并非如此。我怎样才能做到这一点?

powershell
1个回答
2
投票

您的代码的问题是变量

$fieldMap
Hashtable
而不是
OrderedDictionary
。下一个问题是参数
-fieldMap
键入为
Hashtable
而不是
IDictionary
OrderedDictionary

为了让你的代码更高效,你可以使用

.PSObject.Properties
来反映循环中
$item
的属性。您还可以再次使用 OrderedDictionary 构造新对象,然后将其转换为
[pscustomobject] 类型加速器
。这极大地提高了您的代码效率,与此技术相比,
Add-Member
非常慢。
最后,您可以从函数中传输对象,无需

+=

到数组。效率也很低,参见

script-authoring-considerations#array-addition
总结(使用与问题中相同的

$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

© www.soinside.com 2019 - 2024. All rights reserved.