PowerShell完整复制一个数组

16

我想要创建一个已存在数组的完整副本。每次我尝试这样做时它似乎都不起作用。问题在于我正在修改新复制的数组中的对象名称,但它们也会在原始数组中改变。

下面的代码非常简化,因为除了重命名对象名称之外还有很多其他事情发生,但我认为它证明了这一点。

一些示例代码:

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

$新水果

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

谢谢你的帮助。


1
嘿,DarkLite...你上一次吃到美味新鲜的“_peer_”是什么时候? - Matt
“字符串是关键”,来自Scripting Guys,而在我的案例中,水果使演示代码更容易,哈哈。但说实话,如果我必须选择,我更喜欢香蕉。希望你当选,我投了你的票 :) - DarkLite1
你可能把我和别人搞混了,因为我并没有参与竞选(或者我参与了?)。另外,我想指出“peer”这个单词拼错了。 - Matt
总是这么严肃 ;) 修好了,谢谢!你是正确的,投票给了错误的Matt。无论如何,我总是很感激你的帮助,所以特别感谢你。 - DarkLite1
可能是重复的问题,参考 Powershell - 将引用类型数组复制为值类型的方法 - jpaugh
5个回答

19
# Copy the array here
$FruitsCopy = @()
$FruitsCopy = $FruitsCopy + $FruitsOriginal

1
$FruitsCopy = @() + $FruitsOriginal 也可以工作。 - Zout

15
你可以使用序列化来深度克隆你的数组:
你可以使用序列化将数组进行深度复制:
#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()

太棒了!非常感谢Jaco :) - DarkLite1
1
这个方法有“深度”对象限制吗?另外值得注意的是,上述代码仅在 $FruitsOriginal.GetType().IsSerializable -eq $true 的情况下才有效。 - Frank Lesniak
抱歉,还有一件事:如果$FruitsOriginal包含嵌套对象,则每个嵌套对象的.GetType().IsSerializable也必须为$true才能使其正常工作。 - Frank Lesniak

9
自PowerShell 3.0以来,采用与Jaco's answer相同的方法,但使用PSSerializer。 它使用与Export-ClixmlImport-Clixml兼容的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.

这是一个很好的提示!谢谢你的添加。 - DarkLite1
不客气。在我找到这个解决方案之前,我曾经不止一次与 $_.psobject.Copy() 斗争过 :) - Petru Zaharia

2

如果你正在复制一个包含所有“真值”值的对象/值的数组,或者想要快速过滤掉null和“falsey”值,则可以使用以下代码:

$FruitsNew = $FruitsOriginal|?{$_}

0
根据您需要使用对象的方式,以及它们是否足够简单(例如您的示例),您可以将其替换为新的对象。 $NewFruits = $FruitsOriginal | %{ [PSCustomObject]@{ "Tasty Fruits" = $_.Type } }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接