PowerShell скопировать массив полностью

Я пытаюсь создать полную копию существующего массива. Каждый раз, когда я пытаюсь это сделать, это не работает. Дело в том, что я изменяю имена объектов внутри нового скопированного массива, но они также изменяются в исходном массиве.

Приведенный ниже код сильно упрощен, поскольку происходит гораздо больше, чем просто переименование имен объектов, но это подтверждает то, что я думаю.

Пример кода:

Function Get-Fruits {
    Param (
        $Fruits = @('Banana', 'Apple', 'Pear')
    )
    foreach ($F in $Fruits) {
        [PSCustomObject]@{
            Type = $F
        }
    }
}

$FruitsOriginal = Get-Fruits

Function Rename-ObjectName {
    # Copy the array here
    $FruitsNew = $FruitsOriginal # Not a true copy
    $FruitsNew = $FruitsOriginal | % {$_} # Not a true copy
    $FruitsNew = $FruitsOriginal.Clone() # Not a true copy

    $FruitsNew | Get-Member | ? MemberType -EQ NoteProperty | % {

        $Name = $_.Name

        $FruitsNew | % {
            $_ | Add-Member 'Tasty fruits' -NotePropertyValue $_.$Name
            $_.PSObject.Properties.Remove($Name)
        }
    }
}

Rename-ObjectName

Желаемый результат - 2 совершенно разных массива.

$ FruitsOriginal

Type
----
Banana
Apple
Pear

$ FruitsNew

Tasty fruits
------------
Banana
Apple
Pear

Спасибо за помощь.

4 ответа

Решение

Вы можете использовать сериализацию для глубокого клонирования вашего массива:

#Original data
$FruitsOriginal = Get-Fruits

# Serialize and Deserialize data using BinaryFormatter
$ms = New-Object System.IO.MemoryStream
$bf = New-Object System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
$bf.Serialize($ms, $FruitsOriginal)
$ms.Position = 0

#Deep copied data
$FruitsNew = $bf.Deserialize($ms)
$ms.Close()
# Copy the array here
$FruitsCopy = @()
$FruitsCopy = $FruitsCopy + $FruitsOriginal

Начиная с Powershell 3.0, такой же подход, как и у ответа Джако, но с использованием PSSerializer.
Он использует CliXML формат совместим с Export-Clixml & Import-Clixml и лично мне легче читать.
Теоретически поддерживает вложенную иерархию до [int32]::MaxValue Уровни неглубоких

#   Original data
$FruitsOriginal     =    Get-Fruits
#   Serialize and Deserialize data using PSSerializer:
$_TempCliXMLString  =   [System.Management.Automation.PSSerializer]::Serialize($FruitsOriginal, [int32]::MaxValue)
$FruitsNew          =   [System.Management.Automation.PSSerializer]::Deserialize($_TempCliXMLString)
#   Deep copy done.

Если вы копируете массив объектов / значений, который содержит все "правдивые" значения, или хотите быстро отфильтровать нулевые и "ложные" значения, тогда это отлично работает:

$FruitsNew = $FruitsOriginal|?{$_}

В зависимости от того, что вам нужно сделать с объектами, и если они достаточно просты (как в вашем примере), вы можете просто заменить их новым объектом.

$NewFruits = $FruitsOriginal | %{ [PSCustomObject]@{ "Tasty Fruits" = $_.Type } }

Другие вопросы по тегам