Home > OS >  Merge two PSCustomObject tables into a single one with PowerShell
Merge two PSCustomObject tables into a single one with PowerShell

Time:01-31

I want to use PowerShell to merge two tables into one.

#Sample table
$CarList1 = @()
$CarList2 = @()

$CarList1 = [PSCustomObject]@{
    "Brand"           = "Audi";
    "Model"           = "A8";
    "Color"           = "Red";
    "ManufactureDate" = "2000.11.01"
}

$CarList2 = [PSCustomObject]@{
    "Brand"           = "Audi";
    "Model"           = "A4";
    "Color"           = "Green";
    "ManufactureDate" = "1998.11.01"
}

I want to transfer the data of $CarList2 into $CarList1

In the end I expect to have all the data in one table.

Brand Model Color ManufactureDate
----- ----- ----- ---------------
Audi  A8    Red   2000.11.01
Audi  A4    Green 1998.11.01

I have tried various things...

foreach ($property in $CarList2.psobject.Properties) {
    foreach ($array in $CarList2.$($property.Name)) {
        $CarList1.$($property.Name)  = $array
    }
}
$CarList1  = $CarList2

...

I hope you could help me, I can't get it to work.

CodePudding user response:

$CarList1 = $CarList2

This only works if $CarList1 is already an array, which is not the case here, because, even though you tried to initialize it as an array with $CarList1 = @(), that initialization had no effect given that the subsequent $CarList1 = [PSCustomObject]@{ ... } assignment replaced the value with a single object.

Without touching your other code, the simplest solution is to use a type constraint on your compound assignment, which implicitly converts $CarList1 to an array, if needed, and additionally ensures that any future values that get assigned are converted to an [array] ([object[]]) too, if necessary:

# OK: Array concatenation, thanks to the [array] type constraint.
[array] $CarList1  = $CarList2

Note that in order for the operator to perform array concatenation, it is sufficient for the LHS to be an array; if the RHS isn't, it is appended as single element to the output array; if it is, its elements are appended one by one.


It follows from the above that if you had initialized (at least) $CarList1 with such a type constraint, $CarList1 = $CarList2 would have worked as-is:

# Initialize the variables as empty arrays and *type-constrain* them as arrays.
[array] $CarList1 = @()
[array] $CarList2 = @()

# Now, even assigning a *single* object causes an *array* to
# be stored, with on-demand conversion.
$CarList1 = [PSCustomObject]@{
    "Brand"           = "Audi";
    "Model"           = "A8";
    "Color"           = "Red";
    "ManufactureDate" = "2000.11.01"
}

# Ditto
$CarList2 = [PSCustomObject]@{
    "Brand"           = "Audi";
    "Model"           = "A4";
    "Color"           = "Green";
    "ManufactureDate" = "1998.11.01"
}

# Since (at least) $CarList1 now is an array, array concatenation
# now succeeds.
$CarList1  = $CarList2

Of course, in this example you could make do without the separate initialization statements, and just do:

  • [array] $CarList1 = [pscustomobject] @{ ... }, ...
  • or, if type-constraining isn't needed, you can use @(...), the array-subexpression operator to ensure that your single object becomes an array:
    $CarList1 = @([pscustomobject] @{ ... })

CodePudding user response:

mklement0's answer is good, but I'd also like to raise awareness of PowerShell's array operator: @( ... ). Anything you put inside is treated as an array.

$CarList1 = @($CarList1)   $CarList2

In this case, rename your variables to $Car1 and $Car2 for the sake of sanity ;-)

Write-Output is also a good one to be aware of:

$CarList = $Car1, $Car2 | Write-Output
  • Related