遍历多维度的 PowerShell JSON 对象

huangapple go评论68阅读模式
英文:

looping through powershell of multiple dimensions json object

问题

我尝试使用foreach和foreach-object,甚至使用convertFrom-json也无法迭代其中的任何值,所以我对这部分有点困惑 - 有什么方法可以迭代每个单元格吗?

我尝试了以下方法,但没有成功:

foreach ($sublist in $data) { 
    foreach ($item in $sublist){ 
        Write-Host ("the value is :"+$item) 
    } 
}

我想要迭代并获取Timestamp的相应值,即对于test-1234,它是2023-07-11T04:00:24+00:00,那么我应该如何更新循环?

a                            b
test-1234                  2023-07-11T04:00:24+00:00
sb-00091                   2023-07-11T04:00:21+00:00

是否有任何书籍或在线文章可以供我参考?

如果我有以下数据结构,那么我应该如何迭代:

[
    [
        "test-1234",
        "2023-07-17T04:00:18+00:00",
        {
            "Code": 8,
            "Name": "running"
        }
    ],
    [
        "sb-00091",
        "2023-07-17T04:00:16+00:00",
        {
            "Code": 16,
            "Name": "running"
        }
    ]
]

输出应该如下所示:

a                 b                            c            d
test-1234       2023-07-11T04:00:24+00:00      8          running
sb-00091        2023-07-11T04:00:21+00:00     16          running
英文:

I have checked with foreach and foreach-object but unable to iterate any value out of it even using convertFrom-json, so I'm little bit clueless on this part - any idea how to iterate though every cell of it ?
I have tried with the below but it didn't work out

> foreach ($sublist in $data) { foreach ($item in $sublist){ Write-Host
> ("the value is :"+$item) } }

[
    [
        [
            "test-1234",
            "2023-07-11T04:00:24+00:00"
        ]
    ],
    [
        [
            "sb-00091",
            "2023-07-11T04:00:21+00:00"
        ]
    ]
]

I would like to iterate through and would like to get the corresponding value of Timestamp i.e. for test-1234 it is 2023-07-11T04:00:24+00:00 , then how should I need to update the loop

a                            b
test-1234                  2023-07-11T04:00:24+00:00
sb-00091                   2023-07-11T04:00:21+00:00

Is there any book or online article available if I can go through it

If I have the below data structure then how should I iterate

    [
        [
            "test-1234",
            "2023-07-17T04:00:18+00:00",
            {
                "Code": 8,
                "Name": "running"
            }
        ]
    ],
    [
        [
            "sb-00091",
            "2023-07-17T04:00:16+00:00",
            {
                "Code": 16,
                "Name": "running"
            }
        ]
    ]
]

output should be in this way

a                 b                            c            d
test-1234       2023-07-11T04:00:24+00:00      8          running
sb-00091        2023-07-11T04:00:21+00:00     16          running

答案1

得分: 4

使用建议的解决方案从您之前的问题中提取一个扁平的值列表,然后从每对值创建一个新对象:

$json = Get-Content path\to\json.json -Raw | ConvertFrom-Json
$queue = [System.Collections.Generic.Queue[object]]::new()
$queue.Enqueue($json)

$extractedValues = while ($queue.Count) {
    $items = $queue.Dequeue()
    foreach ($item in $items) {
        if ($item -is [System.Collections.ICollection]) {
            $queue.Enqueue($item)
            continue
        }
        $item
    }
}

$results = for ($i = 0; $i -lt $extractedValues.Count; $i += 2) {
  [PSCustomObject]@{
    A = $extractedValues[$i]
    B = $extractedValues[$i+1]
  }
}

这种方法在数据不一致的情况下可能不起作用(例如,如果内部数组中的第二个值可能不是字符串),但您可以修改先前的解决方案以测试给定集合是否具有两个元素并且第一个元素是字符串:

$json = Get-Content path\to\json.json -Raw | ConvertFrom-Json
$queue = [System.Collections.Generic.Queue[object]]::new()
$queue.Enqueue($json)

$results = while ($queue.Count) {
    $items = $queue.Dequeue()
    foreach ($item in $items) {
        if ($item -is [System.Collections.ICollection]) {
            if ($item.Count -eq 2 -and $item[0] -is [string]){
                # we've reached a leaf value, output as an object
                [PSCustomObject]@{
                    A = $item[0]
                    B = $item[1]
                }
            }
            else {
                # otherwise, continue traversing the structure
                $queue.Enqueue($item)
            }
            continue
        }
        $item
    }
}
英文:

Use the suggested solution from your previous question to extract a flat list of values, then create a new object from each pair:

$json = Get-Content path\to\json.json -Raw | ConvertFrom-Json
$queue = [System.Collections.Generic.Queue[object]]::new()
$queue.Enqueue($json)

$extractedValues = while ($queue.Count) {
    $items = $queue.Dequeue()
    foreach ($item in $items) {
        if ($item -is [System.Collections.ICollection]) {
            $queue.Enqueue($item)
            continue
        }
        $item
    }
}

$results = for ($i = 0; $i -lt $extractedValues; $i += 2) {
  [PSCustomObject]@{
    A = $extractedValues[$i]
    B = $extractedValues[$i+1]
  }
}

This approach might not work if the data isn't uniform (eg. if the second value in the inner array might not be a string), but you could modify the previous solution to test for whether a given collection has a count of two and a string in the first slot:

$json = Get-Content path\to\json.json -Raw | ConvertFrom-Json
$queue = [System.Collections.Generic.Queue[object]]::new()
$queue.Enqueue($json)

$results = while ($queue.Count) {
    $items = $queue.Dequeue()
    foreach ($item in $items) {
        if ($item -is [System.Collections.ICollection]) {
            if ($item.Count -eq 2 -and $item[0] -is [string]){
                # we've reached a leaf value, output as object
                [PSCustomObject]@{
                    A = $item[0]
                    B = $item[1]
                }
            }
            else {
                # otherwise, continue traversing the structure
                $queue.Enqueue($item)
            }
            continue
        }
        $item
    }
}

答案2

得分: 2

类似于Mathias的最后一个示例,但是后续将其强制转换为char的索引递增(65将变成A)。缺点是,如果数组的计数不统一,您最终会得到非规范化的对象或_属性不统一的对象_。

$json = Get-Content path\to\stuff.json -Raw | ConvertFrom-Json
$queue = [System.Collections.Generic.Queue[object]]::new()
$queue.Enqueue($json)

$out = [ordered]@{}
while ($queue.Count) {
    $items = $queue.Dequeue()
    $char = 65

    foreach ($item in $items) {
        if ($item -isnot [System.Collections.ICollection]) {
            $out[[char] $char++] = $item
            continue
        }

        $queue.Enqueue($item)
    }

    if ($out.Keys) {
        [pscustomobject] $out
        $out.Clear()
    }
}

输出应该如下所示:

A         B
-         -
test-1234 7/11/2023 1:00:24 AM
sb-00091  7/11/2023 1:00:21 AM
英文:

Similar approach to Mathias's last example but incrementing an index that is coerced into a char later (65 would be A). Downside is that if arrays don't have uniform counts you would end up with not normalized objects or objects not having uniform properties.

$json = Get-Content path\to\stuff.json -Raw | ConvertFrom-Json
$queue = [System.Collections.Generic.Queue[object]]::new()
$queue.Enqueue($json)

$out = [ordered]@{}
while ($queue.Count) {
    $items = $queue.Dequeue()
    $char = 65

    foreach ($item in $items) {
        if ($item -isnot [System.Collections.ICollection]) {
            $out[[char] $char++] = $item
            continue
        }

        $queue.Enqueue($item)
    }

    if ($out.Keys) {
        [pscustomobject] $out
        $out.Clear()
    }
}

Output should look like:

A         B
-         -
test-1234 7/11/2023 1:00:24 AM
sb-00091  7/11/2023 1:00:21 AM

huangapple
  • 本文由 发表于 2023年7月14日 01:08:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/76681805.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定