PowerShell是否有一个"窗口"功能?

时间:2017-01-06 15:30:47

标签: powershell functional-programming pipeline

我正在寻找一个"窗口"功能类似于F#' Seq.windowed或反应扩展程序Window。看起来它会由Select-Object(已经具有take / skip功能)之类的提供,但它不是。

如果没有任何可用的东西,任何有关实施"窗口"的想法没有不必要的程序循环?

我正在寻找适合PowerShell管道的东西。

2 个答案:

答案 0 :(得分:3)

您需要使用某种队列来累积和旋转足够的先前管道项:

function Window {
    param($Size)
    begin {
        $Queue = [Collections.Queue]::new($Size)
    }
    process {
        $Queue.Enqueue($_)
        if($Queue.Count -eq $Size) {
            @(
                ,$Queue.ToArray()
                [void]$Queue.Dequeue()
            )
        }
    }
}

你可以像这样使用它:

1..10 | Window 4 | Window 3 | Format-Custom -Expand CoreOnly

答案 1 :(得分:1)

据我所知,没有这样的内置功能。 PowerShell对管道的处理,特别是它对展开枚举的强烈坚持,使得编写一个函数来管道变得有点困难,但作为一般表达式:

$a = 1..10  # an array contain 1 through 10
$w = 4      # window size of 4

0..($a.Length-$w) | ForEach-Object -Process {
    $a[$_..($_+$w-1)]
}

这会处理您想要的窗口数组。这样更容易看到:

0..($a.Length-$w) | ForEach-Object -Process {
    "This is my window: $($a[$_..($_+$w-1)])"
}

问题是,如果您尝试以这种方式执行上述操作:

0..($a.Length-$w) | ForEach-Object -Process {
    $a[$_..($_+$w-1)]
} | ForEach-Object -Process {
    "This is my window: $_"
}

你会非常失望,因为“窗口”数组在被传送到ForEach-Object之前已展开;你编写的任何管道函数都会遇到问题。

在函数中没有办法补偿它,你必须小心在ForEach-Object块中使用它,因为即使在赋值:

$myWindows = 0..($a.Length-$w) | ForEach-Object -Process {
    $a[$_..($_+$w-1)]
}

它将被展开。

那么你需要类似的东西:

0..($a.Length-$w) | ForEach-Object -Begin {
    $myWindows = @()
} -Process {
    $myWindows += @(,$a[$_..($_+$w-1)])
}

然后您可以使用:

$myWindows | ForEach-Object -Process {
    "This is my window: $_"
}