已解决:有人在 PowerShell 中做 Advent of Code 吗?

发布: (2026年1月1日 GMT+8 06:26)
9 min read
原文: Dev.to

Source: Dev.to

执行摘要

TL;DR: 在 PowerShell 中解决 Advent of Code(AoC)面临诸如冗长的输入解析和复杂算法的性能瓶颈等挑战。
解决方案包括:

  • 利用符合惯用法的 PowerShell 管道和 .NET 集成。
  • 通过 C# 互操作提升关键部分的速度。
  • 编排外部的高性能优化工具。

为什么使用惯用的 PowerShell?

  • 面向对象的管道 – 链接 cmdlet,传递对象,保持代码可读性。
  • 内置 cmdlet – 强大的字符串操作、正则表达式和文件处理。
  • 直接 .NET 调用 – 当 cmdlet 不足时,访问任何 .NET 类型。

对于许多 AoC(Advent of Code)谜题,这种方法是 自然可读、且 足够 的。

当 PowerShell 碰到性能瓶颈

  • 大型数据集、深度递归或密集的模拟可能导致 PowerShell 脚本运行时间从秒级变为分钟级。
  • 高级数据结构(优先队列、自定义图、不可变集合)在纯 PowerShell 中实现起来效率低下且繁琐。
  • 缺少算法原语——PowerShell 没有 Python 或 C# 那样丰富的标准库辅助工具。

解决方案: 使用 C# 互操作Add-Type)编写热点代码,然后在 PowerShell 中调用编译后的类。

编排外部工具

PowerShell 作为“胶水”,在以下方面表现出色:

  1. 准备输入。
  2. 执行外部高度优化的二进制文件(例如 grep、自定义 C/C++ 工具)。
  3. 将输出处理回 PowerShell 对象。

实用 PowerShell 模式

1. 从分隔输入文件中求和

input.txt

10,20,30
15,25,35
# 读取每一行,按逗号分割,转换为整数并求和
$totalSum = Get-Content -Path 'input.txt' |
    ForEach-Object { $_ -split ',' } |
    ForEach-Object { [int]$_ } |
    Measure-Object -Sum |
    Select-Object -ExpandProperty Sum

Write-Host "总和: $totalSum"

2. 使用网格 / 矩阵

grid.txt(示例)

#.##
.#.#
##.#
# 将网格加载为字符数组的数组
$grid = Get-Content -Path 'grid.txt' | ForEach-Object { $_.ToCharArray() }

# 访问元素(第 1 行,第 2 列)
Write-Host "元素位于 (1,2): $($grid[1][2])"

# 遍历网格
for ($row = 0; $row -lt $grid.Length; $row++) {
    for ($col = 0; $col -lt $grid[$row].Length; $col++) {
        Write-Host "($row,$col) = $($grid[$row][$col])"
    }
}

3. 使用 .NET 集合提升性能与灵活性

# 可变的泛型 List[int]
$myList = [System.Collections.Generic.List[int]]::new()
$myList.Add(10)
$myList.Add(20)
$myList.Add(30)

Write-Host "列表计数: $($myList.Count)"
$myList.Remove(20)
Write-Host "移除后的列表: $($myList -join ', ')"

# 字典(PowerShell 中的哈希表)
$myDictionary = @{}
$myDictionary["apple"]  = 1
$myDictionary["banana"] = 2

Write-Host "apple 的值: $($myDictionary["apple"])"

C# 热路径代码的互操作

当“惯用的 PowerShell”速度不够快时,直接嵌入 C#:

Add-Type @"
using System;
using System.Collections.Generic;

public static class AoCHelper {
    // 示例:快速求整数数组的和
    public static long FastSum(int[] numbers) {
        long sum = 0;
        foreach (int n in numbers) sum += n;
        return sum;
    }

    // 在此添加更多性能关键的方法
}
"@

# 从 PowerShell 使用已编译的类
$numbers = 1..1_000_000
$sum = [AoCHelper]::FastSum($numbers)
Write-Host "Fast sum = $sum"

在 C# 中编写性能关键的算法,使用 Add-Type 编译,然后像普通 PowerShell 方法一样调用它。

综合运用

  1. 使用 习惯性的 PowerShell 进行解析和编排。
  2. 识别 性能瓶颈(使用 Measure-Command 或分析工具)。
  3. 热点路径的代码段替换为 C# 互操作或外部工具。
  4. 通过 限制互操作的范围,保持整体脚本的可读性和可维护性。

最终思考

  • Advent of Code 是一个极好的练习场,能够探索 PowerShell 的优势与局限。
  • 通过结合 管道中心脚本.NET 强大功能C# 互操作外部实用工具,你可以高效地解决即使是最棘手的 AoC 谜题,同时保持 PowerShell 作为优秀自动化语言的清晰可读性。

快速斐波那契序列计算(C#)

我们将定义一个 C# 类,其中包含一个静态方法,用于快速计算第 N 个斐波那契数。

$cSharpCode = @'
using System;

public static class FibonacciCalculator
{
    public static long GetNthFibonacci(int n)
    {
        if (n  left.Equals(right);
    public static bool operator !=(Point left, Point right) => !(left == right);
}
'@

Add-Type -TypeDefinition $cSharpCode -Language CSharp

# Create and use Point structs
$p1 = New-Object Point(10, 20)
$p2 = New-Object Point(10, 20)
$p3 = New-Object Point(5, 5)

Write-Host "Point 1: $p1"
Write-Host "Point 2: $p2"
Write-Host "Point 3: $p3"

if ($p1 -eq $p2) { Write-Host "P1 and P2 are equal." }
if ($p1 -ne $p3) { Write-Host "P1 and P3 are not equal." }

利用外部工具

有时,针对特定子问题,最有效的解决方案并不是用 PowerShell 或 C# 编写,而是调用已有的、高度优化的外部工具。PowerShell 擅长编排这些工具、在它们之间传递数据并整合它们的输出。

示例:使用 WSL grep 进行高级模式匹配

# Assume input.txt contains:
# This is a test line.
# Another line with the word test.
# No match here.

# Find all lines containing "test"
$matchedLines = wsl.exe grep "test" "input.txt"

Write-Host "Lines containing 'test':"
$matchedLines | ForEach-Object { Write-Host $_ }

示例:调用自定义编译可执行文件

# Create a dummy input file for the external tool
Set-Content -Path 'puzzle_map.txt' -Value @'
###########
#S........#
###.......#
#.........#
#.......E.#
###########
'@

# Run the external pathfinder.exe (takes a file path and returns the shortest path length)
$pathResult = & ".\pathfinder.exe" "puzzle_map.txt"

Write-Host "Pathfinder result: $pathResult"

# If the external tool outputs JSON, you can parse it:
# $jsonResult = & ".\myparser.exe" "data.json" | ConvertFrom-Json
# $value = $jsonResult.SomeProperty

示例:将数据管道传递给/从外部工具

PowerShell 的管道可以与外部进程交互,将数据送入它们的标准输入并捕获它们的标准输出。

# Simulate an external tool that counts characters (e.g., `wc -c` on Linux)
# For Windows we’ll use a simple Python script (counter.py):
#   import sys
#   print(sum(len(line) for line in sys.stdin))

$dataToSend = @(
    "Line 1"
    "Another Line"
    "Last One"
)

# Pipe data to the Python script and capture its output
# Ensure python.exe is in your PATH or specify its full path
$charCount = $dataToSend | python.exe - ".\counter.py"

Write-Host "Total characters (excluding newlines): $charCount"

选择合适的方法

功能 / 方法纯 PowerShell(惯用)C# 互操作 (Add-Type)外部工具编排
可读性与可维护性高(针对 PowerShell 用户)中低(PowerShell 与 C# 混合)中等(PowerShell 进行编排;外部逻辑不透明)
性能中低(解释执行,对象开销)高(编译的 C# 以本机速度运行)非常高(利用高度优化的外部二进制文件)

选择合适的方法取决于具体的 Advent of Code 题目、您对语言/工具的熟悉程度以及性能需求。使用 PowerShell 作为粘合剂,C# 负责热点路径计算,在外部工具能够提供明显优势时使用它们。

Development Effort

  • Low to Medium – familiar language, rapid prototyping.
  • Medium to High – requires C# knowledge, debugging can be split.
  • Medium – requires understanding external tool APIs, input/output.

Complexity Handled

  • 适用于大多数文本处理、数据操作、较简单的算法。
  • 非常适合复杂算法、自定义数据结构、性能关键的逻辑。
  • 非常适用于已有工具完美匹配的特定子问题。

适用于 AoC

  • 大多数谜题的首选,尤其是第 1 部分。
  • 适合第 2 部分的谜题,当第 1 部分的解法太慢时。
  • 针对特定问题的细分领域(例如,繁重的正则表达式,如果存在相应工具则用于特定图算法)。

调试体验

  • 优秀 在 PowerShell ISE/VS Code 中。
  • 一般 – 脚本的 PowerShell 调试器,C# 逻辑在 PowerShell 中常常不透明。
  • 一般 – 编排的 PowerShell 调试器,外部工具调试分离。

👉 阅读原文请访问 TechResolve.blog

Back to Blog

相关文章

阅读更多 »

C# Smart Enums:高级

封面图片:C Smart Enums:advanced https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-upload...