Windows PowerShellでProject Euler(37)

Problem 30

これは重複組合せを生成する問題です。PowerShellの関数はほぼジェネレータなので、簡単に生成できます。
22秒かかりました。


PowerShellのシリーズはここまでです。

function fold($f, $x0) {
    begin   { $x = $x0 }
    process { $x = &$f $x $_ }
    end     { $x }
}

function pow($n, $e) {
    return 1..$e | fold { $args[0] * $n } 1
}

function digits($n) {
    while($n -gt 0) {
        $r = $n % 10
        $r
        $n = ($n - $r) / 10
    }
}

function number($a) {
    $a | fold { $args[0] * 10 + $args[1] } 0
}

function repeated_combinations($a, $n) {
    if($n -eq 1) {
        $a
    }
    else {
        foreach($k in 0..($a.length-1)) {
            $e = $a[$k]
            repeated_combinations $a[$k..($a.length-1)] ($n - 1) |
                                    foreach { ,(@($e) + $_) }
        }
    }
}

function calc_limit($E) {
    for($n = 1; $n * $pows[9] -ge (pow 10 $n); ++$n) {
        
    }
    $n
}

function sum_pows($a) {
    ($a | foreach { $pows[$_] } | measure -sum).sum
}

function sort_by_digits($n) {
    number (digits $n | sort)
}

function matches($a) {
    $m = number $a
    $n = sort_by_digits (sum_pows $_)
    $m -eq $n
}

$watch = New-Object System.Diagnostics.Stopwatch
$watch.Start();
$E = 5
$pows = 0..9 | foreach { pow $_ $E }
$L = calc_limit $E
(repeated_combinations (0..9) $L | where { matches $_ } |
        foreach { sum_pows $_ } | measure -sum).sum - 1
$watch.Stop();
$watch.Elapsed.TotalMilliSeconds / 1000