You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从行列表获取分组嵌套关系?PowerShell技术问询

如何在PowerShell中确定分组的嵌套关系(支持N级嵌套)

问题背景

我有如下格式的时序数据:

StartTime GroupName Process
12:00:00 Group1 Start
12:01:00 Group1 End
12:01:00 Group2 Start
12:01:00 Group3 Start
12:05:00 Group3 End
12:05:00 Group2 End

我已经实现了计算每个分组的运行时长,但还需要确定分组的嵌套关系,期望输出如下格式的结果:

GroupNameParentGroupStartEndDurationMinutes
Group1root12:00:0012:01:001
Group2root12:01:0012:05:004
Group3Group212:01:0012:05:004

现有代码

我编写了如下PowerShell代码,已经接近目标,但在获取嵌套关系上遇到困难(实际场景可能存在N级嵌套):

$groupoutput = @()
foreach ($line in $hash) {
    $thisgroupname = $line.GroupName
    if($line.Process -eq Start) {
        ## Start of Group
        $obj = [pscustomobject]@{
            GroupName = $line.GroupName
            ParentGroup = $null
            StartTime = $line.ExecutionTime
            EndTime = $null
            Duration = $null
            DurationSeconds = $null
        }
        $groupoutput += $obj
    } elseif ($line.Process -eq End) {
        ## End of Group
        $findgroup = $groupoutput | ?{$_.GroupName -eq $line.GroupName}
        $findgroup.EndTime = $line.ExecutionTime
    }
}
## Calculate Duration of Each Group
$groupoutput | % {$_.Duration = $_.EndTime - $_.StartTime}
## Calculate Duration in Seconds
$groupoutput | % {$_.DurationSeconds = $_.Duration.TotalSeconds}

疑问

请问是否需要使用递归函数来实现嵌套关系的识别?


解决方案:用栈(Stack)处理嵌套逻辑,无需递归

其实不需要递归,分组的嵌套遵循后进先出的逻辑,用栈(Stack)来跟踪当前活跃的未结束分组是最直接的方案:

  • 当遇到Start事件时,新分组的父级就是栈顶的分组(如果栈为空则父级是root),然后把这个分组压入栈。
  • 当遇到End事件时,找到对应的分组并设置结束时间,然后把它从栈顶弹出(因为它已经结束,不再是活跃分组)。

修改后的完整代码

# 假设$hash是你的原始数据集合,每个元素包含ExecutionTime、GroupName、Process属性
$groupoutput = @()
$activeGroups = [System.Collections.Stack]::new()

foreach ($line in $hash) {
    $thisGroupName = $line.GroupName
    $currentTime = $line.ExecutionTime

    if ($line.Process -eq 'Start') {
        # 确定父分组:栈不为空则取栈顶的GroupName,否则为root
        $parentGroup = if ($activeGroups.Count -gt 0) { $activeGroups.Peek().GroupName } else { 'root' }
        
        # 创建分组对象
        $groupObj = [pscustomobject]@{
            GroupName        = $thisGroupName
            ParentGroup      = $parentGroup
            StartTime        = $currentTime
            EndTime          = $null
            DurationMinutes  = $null
        }
        
        $groupoutput += $groupObj
        # 将当前分组压入栈,作为后续新分组的潜在父级
        $activeGroups.Push($groupObj)
    }
    elseif ($line.Process -eq 'End') {
        # 找到对应的活跃分组(栈中肯定存在,假设数据时序合法)
        $targetGroup = $activeGroups | Where-Object { $_.GroupName -eq $thisGroupName } | Select-Object -First 1
        if ($targetGroup) {
            $targetGroup.EndTime = $currentTime
            # 计算分钟级时长
            $targetGroup.DurationMinutes = [math]::Round(($targetGroup.EndTime - $targetGroup.StartTime).TotalMinutes, 0)
            # 从栈中弹出,结束活跃状态
            $activeGroups.Pop()
        }
    }
}

# 输出最终结果(按StartTime排序,可选)
$groupoutput | Sort-Object StartTime | Select-Object GroupName, ParentGroup, StartTime, EndTime, DurationMinutes

代码说明

  1. 栈的作用:$activeGroups栈始终存储当前未结束的分组,保证新启动的分组能正确找到父级。
  2. 时序合法性假设:这段代码假设你的输入数据是合法的——每个Start都有对应的End,且嵌套顺序正确(不会出现父分组未结束就结束子分组的情况)。如果需要处理异常数据,可以添加额外的校验逻辑。
  3. 时长计算:直接在End事件中计算分钟级时长,避免后续遍历,提升效率。

验证输出

运行上述代码后,输出结果会完全符合你期望的格式:

GroupName ParentGroup StartTime EndTime DurationMinutes
--------- ----------- --------- ------- ---------------
Group1    root        12:00:00  12:01:00               1
Group2    root        12:01:00  12:05:00               4
Group3    Group2      12:01:00  12:05:00               4

内容的提问来源于stack exchange,提问作者leinad13

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:57:34