使用中间变量来处理数组(引用类型)

时间:2016-07-31 03:12:13

标签: arrays powershell

我正在尝试在此脚本中使用$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;

2 个答案:

答案 0 :(得分:0)

所有数组元素都引用一个实际变量:$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
}

答案 1 :(得分:0)

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

演示:

PS C:\> $o = '{"foo":{"bar":42},"baz":23}' | ConvertFrom-Json
PS C:\> $o | Format-Custom *

class PSCustomObject
{
  foo =
    class PSCustomObject
    {
      bar = 42
    }
  baz = 23
}

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

如果更改bar$o1上的嵌套属性$o2,则它在两个对象上都包含上次设置为其中任何一个的值:

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,但它并不像人们想象的那么简单明了。通常,在您的问题的评论中建议的@PetSerAl多次创建对象需要花费更少的精力(和更简单的代码)。

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

$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数据出现问题。