【问题标题】:Using intermediate variable to work with array (reference type)使用中间变量处理数组(引用类型)
【发布时间】:2016-07-31 03:12:12
【问题描述】:

我正在尝试在此脚本中使用$a 变量来处理中间步骤,这样我就不必重复使用$array[$array.Count-1]$prop 也是如此。但是,值正在被循环中的最后一个值覆盖。

$guests = Import-Csv -Path C:\Users\shant_000\Desktop\UploadGuest_test.csv
$output = gc '.\Sample Json.json' | ConvertFrom-Json
$array = New-Object System.Collections.ArrayList;

foreach ($g in $guests) {
    $array.Add($output);
    $a = $array[$array.Count-1];

    $a.Username = $g.'EmailAddress';
    $a.DisplayName = $g.'FirstName' + ' ' + $g.'LastName';
    $a.Password = $g.'LastName' + '123';
    $a.Email = $g.'EmailAddress';

    foreach ($i in $a.ProfileProperties.Count) {
        $j = $i - 1;

        $prop = $a.ProfileProperties[$j];

        if ($prop.PropertyName -eq "FirstName") {
            $prop.PropertyValue = $g.'FirstName';
        } elseif ($prop.PropertyName -eq "LastName") {
            $prop.PropertyValue = $g.'LastName';
        }

        $a.ProfileProperties[$j] = $prop;
    }

    $array[$array.Count-1] = $a;
}

$array;

【问题讨论】:

  • $output = gc '.\Sample Json.json' | ConvertFrom-Json -> $outputJson = gc '.\Sample Json.json', $array.Add($output) -> [void]$array.Add(($outputJson | ConvertFrom-Json))

标签: arrays powershell


【解决方案1】:

所有数组元素都引用一个实际变量:$output

通过重复 JSON 解析每次创建一个全新的对象:

$jsontext = gc '.\Sample Json.json'
..........
foreach ($g in $guests) {
    $a = $jsontext | ConvertFrom-Json

    # process $a
    # ............

    $array.Add($a) >$null
}

如果 JSON 文件很大并且您只更改了其中的一小部分,您可以通过.PSObject.Copy() 对更改的部分(及其整个父链)使用更快的克隆技术:

foreach ($g in $guests) {
    $a = $output.PSObject.Copy()
    # ............

    $a.ProfileProperties = $a.ProfileProperties.PSObject.Copy()
    # ............
    foreach ($i in $a.ProfileProperties.Count) {
        # ............
        $prop = $a.ProfileProperties[$j].PSObject.Copy();
        # ............
    }

    $array.Add($a) >$null
}

【讨论】:

【解决方案2】:

正如其他人所指出的,附加 $object 会附加对同一个对象的引用,因此您会不断更改列表中所有元素的值。不幸的是,如果您的 JSON 数据结构具有嵌套对象,建议的方法 @wOxxOm(我最初认为也可以)不起作用,因为 Copy() 仅克隆最顶层的对象,而嵌套对象仍然引用其原始对象。

演示:

PS C:\> $o = '{"foo":{"bar":42},"baz":23}' | ConvertFrom-Json
PS C:\> $o |格式-自定义 *

PSCustomObject 类
{
  富=
    类 PSCustomObject
    {
      酒吧 = 42
    }
  巴兹 = 23
}

PS C:\> $o1 = $o
PS C:\> $o2 = $o.PSObject.Copy()

如果您更改 bar$o1$o2 的嵌套属性 bar,则这两个对象上的值都是最后设置为其中任何一个的值:

PS C:\> $o1.foo.bar = 23
PS C:\> $o2.foo.bar = 24
PS C:\> $o1.foo.bar
24
PS C:\> $o2.foo.bar
24

仅当您更改最顶层对象的属性时,您才会得到$o1$o2 之间的区别:

PS C:\> $o1.baz = 5
PS C:\> $o.baz
5
PS C:\> $o1.baz
5
PS C:\> $o2.baz
23

虽然您可以使用deep copy,但它并不像人们想的那么简单直接。通常,只需按照 cmets 中针对您的问题所建议的 @PetSerAl 多次创建对象即可花费更少的精力(和更简单的代码)。

我还建议避免在循环中附加到数组(或数组列表)。您可以简单地在循环中回显您的对象,并通过将循环分配给变量来将整个输出收集为列表/数组:

$json = Get-Content '.\Sample Json.json' -Raw
$array = foreach ($g in $guests) {
    $a = $json | ConvertFrom-Json   # create new object

    $a.Username = $g.'EmailAddress'
    ...

    $a   # echo object, so it can be collected in $array
}

在 PowerShell v3 和更新版本上使用 Get-Content -Raw(或在早期版本上使用 Get-Content | Out-String)以避免 JSON 文件中的多行 JSON 数据出现问题。

【讨论】:

    猜你喜欢
    • 2010-12-14
    • 2016-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-03
    • 2017-09-11
    • 2011-08-27
    相关资源
    最近更新 更多