参加しました。今回はタイミングよく本会場の近くにいたため、現地参加してきました。
いろんな人にお会いできてよかったなあと思いました。
今回も参加記として自分の解答と復習のPowerShell解を書きます。
問題と解説は当日の配信をご覧ください
問題1
replay.txt
はメールの件名、送信者、受信者、送信時刻が行区切りで書かれているデータです。このデータの中から、送信と返信のペアを見つけて、返信までに何時間かかったかを出力するという問題。
$ join -j9 ShellGeiData/vol.64/reply.txt{,} | awk '"Re:"$4==$NF{print $4, $3, $7, $1"T"$2, $5"T"$6}' | teip -f 4,5 -- date -f- +%s | awk '{print $1,$2,$3,($5-$4)/3600}' | sort -k4n
やったー 太郎->花子 花子->太郎 3.18278
首記の件 花子->太郎 太郎->花子 22.8919
こんにちは 太郎->花子 花子->太郎 25.1964
げんき? 太郎->花子 花子->太郎 52.0769
毎々お世話になります 太郎->花子 花子->太郎 81.9994
join -j9
でクロスジョインすることでペアを全列挙します。そこから欲しいペアだけawk
で出力していくやり方を採用しました。awk
で状態を持たなくていいのでちょっと楽ですけど、カラムが多くて数えるのが面倒です。
ペアを出したあとは、teip
で日付をUnixTimeにして、時間の差分を取るって感じにしました。dateutils
のdatediff
だともうちょっと簡単に書けたかもです。
PowerShell解もやってみます。
$ cat .\ShellGeiData\vol.64\reply.txt | % -Begin {$hash=@{}} { $x=$_ -split ' '; $hash[$x[3]]=@{t=Get-Date -Date ($x[0..1] -join ' '); ft=$x[2]} } -End { $hash.Keys | ?{ $hash["Re:$_"] } | %{ @($_, $hash[$_].ft,$hash["Re:$_"].ft, $hash["Re:$_"].t.Subtract($hash[$_].t).TotalHours) -join ' ' }} | Sort-Object {[decimal]($_ -split ' ')[3]}
やったー 太郎->花子 花子->太郎 3.18277777777778
首記の件 花子->太郎 太郎->花子 22.8919444444444
こんにちは 太郎->花子 花子->太郎 25.1963888888889
げんき? 太郎->花子 花子->太郎 52.0769444444444
毎々お世話になります 太郎->花子 花子->太郎 81.9994444444444
シュッとクロスジョインできなかったので、ForEach-Object
でゴリゴリしました。そんなにいうことはないんですけど、Hashじゃない単純なテキストファイルのソートでSort-Object
を使うとき、列の指定に {($_ -split ' ')[N]}
を使うってのを見てそうなんだ…。ってなりました。
問題2
平均値ゼロ、標準偏差1の正規分布に従う乱数を延々と出力する問題。よくわからない場合は0~1の乱数を12個足して6引くのでもOKとのこと。よくわかんないので後者で行きます。
$ yes | awk 'BEGIN{srand()}{print rand()}' | xargs -n12 | sel -D + 0 | addr -6 | bc | head
-.5806370
.266194
-1.616049118
-.6380601
-.297515
-.5362764
-1.0671419
1.218777
.5491392
-.9868898
はい…。解説することがないぐらいシンプルにできました。ちなみにaddr
はegzactのやつで、右端に文字を追加するっていうコマンドです。sed
でもいいです。
PowerShell解もやってみます
$ while($true) {(Get-Random -SetSeed (Get-Date).Nanosecond -Maximum 1.0 -Count 12 | measure -Sum).Sum - 6}
こちらも解説することはあんまないです。
問題3
mat
ファイルには行列が書かれています。これが対称行列であることを示してください。という問題。
$ cat ShellGeiData/vol.64/mat | rs -T | sel -a 0 | diff - ShellGeiData/vol.64/mat && echo そうだよ || echo ちゃうよ
そうだよ
そうらしいです。rs
の-T
で転置して、diff
が出なければOKって感じですね。
PowerShell解も大体同じになっちゃうんですが、こっちはjuliaでやってみます。
$ diff (("transpose([$((cat .\ShellGeiData\vol.64\mat) -join ';')])" | julia)[1..5] -replace ' +',' ' -replace '^ ') (cat .\ShellGeiData\vol.64\mat); echo $?
True
julia
で転置を計算し、不要な部分を削ってから diff
を取ってます。それだけです
問題4
nums.0
ファイルは、一行に[value] [key]
という形式でデータが書かれたファイルです。
小問1
[key]
で集計し、[value]
の平均値を求めて下さい
小問2
nums.0
の[key]
を付け替えてください。さっき求めた平均値に最も近い[key]
を選ぶようにしてください。
という感じの問題。小問1はさっと行けたんですが…。
$ cat ShellGeiData/vol.64/nums.0 | awk '{c[$2]++;t[$2]+=$1}END{for(k in c) print k, t[k]/c[k]}'
0 5.33333
1 6.33333
2 6
小問2は時間切れになりました。解説によると、平均値を 5.33333 6.33333 6
みたいに1行にしてから、nums.0
の右に連結、awk
で一番近いのを計算しつつ、フィールド番号からキーを付け替えるということでした。むず
問題5
オイラーのファイ関数を実装してください。という問題。
$ echo 12 | factor | zniq | tr -d : | teip -f2- -- sed 's:.*:*(1-1/&):g' | julia
4.0
素因数をuniq
し、k番目の素因数をpk
としたとき、この式はN * (1-1/p1) * (1-1/p2) * ... * (1-1/pk)
となるので、これをシェルで再現すればよいということになりますね。素因数分解といえばfactor
コマンドです。この出力からユニークな素因数一覧を取り出したいです。fmt -1|uniq
みたいなことをすればいいですが、横方向のuniq
をしたいときはegzactのzinq
を使えばサッとできるのでオススメです。あとはteip
で1カラム目以降を(1-1/pk)
の形に整形してjulia
で計算してます。別にjulia
じゃなくてもよいです。
PowerShell解もやってみます。と思ったんですけど、julia
を調べてたらtotient
がありました
juliamath.github.io
$ echo 12 | %{ julia -E "using Primes;totient($_)" }
4
PowerShell解じゃなくない?とはなってます
問題6
小問1
seq 100 |
から初めて、各行の数字に対して互いに素な自然数を列挙してください
小問2
列挙した自然数のリストが、ファイ関数の出力と一致することを確認してください
という問題。時間内にどちらも解けませんでした!
$ seq 100 | xargs -I@ julia -E '(@, [x for x in 1:@ if gcd(@,x) == 1])' | tr -d \(\)
1, [1]
2, [1]
3, [1, 2]
4, [1, 3]
5, [1, 2, 3, 4]
6, [1, 5]
7, [1, 2, 3, 4, 5, 6]
8, [1, 3, 5, 7]
9, [1, 2, 4, 5, 7, 8]
10, [1, 3, 7, 9]
11, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
12, [1, 5, 7, 11]
...
またjulia
です。Pythonみたいなリスト内包表記が使えるってのをみてめっちゃええやんってなりました。
小問2も、ここにちょっと足すだけで解けますね。
$ seq 100 | xargs -I@ julia -E 'using Primes; (@, totient(@), [x for x in 1:@ if gcd(@,x) == 1])' | tr -d \(\)
1, 1, [1]
2, 1, [1]
3, 2, [1, 2]
4, 2, [1, 3]
5, 4, [1, 2, 3, 4]
6, 2, [1, 5]
7, 6, [1, 2, 3, 4, 5, 6]
8, 4, [1, 3, 5, 7]
9, 6, [1, 2, 4, 5, 7, 8]
10, 4, [1, 3, 7, 9]
11, 10, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
12, 4, [1, 5, 7, 11]
...
2要素目にファイ関数の出力を置きました。あとは見比べればいいですね。
PowerShell解はほぼ同じになっちゃうので省略です。
LT
今回自分はLTしませんでしたが、面白い話を聞いたので紹介します。
qiita.com
ジョークRFCのrfc9402の実装をしたっていう内容でした。めっちゃよかった。
感想
以前julia
をオススメされてから少しずつ使ってはいたのですが、今回の問題だと使える場面があって良かったです。これで数学系の問題がきても平気ですね。
今回もとても楽しかったです!企画、運営などありがとうございました!