Just another Ruby porter,

〜2016年9月上旬〜


<Older(,) | Newer(.)> | Recent(/)>> | RDF

2016-09-01 (Thu)

Q6 置き換え #シェル芸

まずは数を数えて、

% grep -o '玉子\|卵' Q6 | sort | uniq -c | sort -n 
     12 卵
     15 玉子

sedで実行できる形式にawkで変換して、

% grep -o '玉子\|卵' Q6 | sort | uniq -c | sort -n | paste -s | awk '$0="s/"$2"/"$4"/g"'
s/卵/玉子/g

できあがり。

% grep -o '玉子\|卵' Q6 | sort | uniq -c | sort -n | paste -s | awk '$0="s/"$2"/"$4"/g"' | sed -f - Q6
玉子玉子玉子玉子玉子玉子玉子玉子玉子玉子玉子玉子玉子玉子玉子玉子玉子玉子玉子玉子玉子玉子玉子玉子玉子玉子玉子

模範解答とほぼ同じだな。


2016-09-02 (Fri)

Q7 同じ数字構成のuniq #シェル芸

そのままだと行数分sortしないといけない問題。
でもちょっと考えると昇順で並んでいるものだけを抜き出せばいいと気づく。

% seq -w 0 99999 | awk -F "" '$1<=$2&&$2<=$3&&$3<=$4&&$4<=$5'
% seq -w 0 99999 | perl -F\| -ane 'print if $F[0]<=$F[1]&&$F[1]<=$F[2]&&$F[2]<=$F[3]&&$F[3]<=$F[4]'
% seq -w 0 99999 | ruby -F\| -ane 'print if $F[0]<=$F[1]&&$F[1]<=$F[2]&&$F[2]<=$F[3]&&$F[3]<=$F[4]'

perlとrubyはまったく同じである。
5桁ぐらいなら全部書いちゃったほうが短いが、もっと桁が増えたときは面倒。
というわけで別解。gawkにはasortという関数が存在するのでこれを利用する。
各桁ごとにsplitして、sortしてjoinして!b[$0]++でuniq。
OFSは空白になっているので""にする。

% seq -w 0 99999 | gawk '{split($0,a,"");asort(a);for(i in a)$i=a[i]}!b[$0]++' OFS=

rubyやperlならsortして自分自身と等しい数字ならという条件でいける。

% seq -w 0 99999 | ruby -lne 'print if $_.chars.sort.join==$_'
% seq -w 0 99999 | perl -ne 'print if $_==join("",sort(/./g))'

jqでやってみたが面白みに欠ける。

% seq -w 0 99999 | jq -sRr 'split("\n")|map(select(.==(split("")|sort|join(""))))[:-1][]'

最後にzshで。

% time seq -w 0 99999 | zsh -c 'while read a;do [ $a = ${(j::)${(os::)a}} ] && echo $a;done'

2016-09-03 (Sat)

Q8-1 1から7をすべてを含む7桁の組み合わせ #シェル芸

sedで同じ数字が出てくる正規表現は\(.\).*\1なので、dで消せばいい。

% time seq 1234567 7654321 | sed '/[890]/d;/\(.\).*\1/d' > q
seq 1234567 7654321  0.26s user 0.04s system 7% cpu 3.992 total
sed '/[890]/d;/\(.\).*\1/d' > q  3.98s user 0.02s system 99% cpu 4.000 total

ちょっと時間がかかる。マルチコアの場合2つに分けてパイプにつないだほうが速くなる。

% time seq 1234567 7654321 | sed '/[890]/d' | sed '/\(.\).*\1/d' > q
seq 1234567 7654321  0.34s user 0.05s system 12% cpu 3.142 total
sed '/[890]/d'  1.52s user 0.05s system 49% cpu 3.150 total
sed '/\(.\).*\1/d' > q  2.92s user 0.00s system 91% cpu 3.180 total

同じことをgrepでやると

% time seq 1234567 7654321 | grep -v -e '[890]' -e '\(.\).*\1' > q
seq 1234567 7654321  0.14s user 0.03s system 3% cpu 4.586 total
grep -v -e '[890]' -e '\(.\).*\1' > q  4.58s user 0.02s system 99% cpu 4.596 total
% time seq 1234567 7654321 | grep -v '[890]' | grep -v '\(.\).*\1' > q
seq 1234567 7654321  0.14s user 0.02s system 5% cpu 3.000 total
grep -v '[890]'  0.30s user 0.01s system 10% cpu 3.000 total
grep -v '\(.\).*\1' > q  3.04s user 0.01s system 99% cpu 3.047 total

だいたい似たような感じになる。PCREを使わせると、

% time seq 1234567 7654321 | grep -v '[890]' | grep -Pv '(.).*\1' > q
seq 1234567 7654321  0.15s user 0.00s system 33% cpu 0.459 total
grep -v '[890]'  0.29s user 0.03s system 69% cpu 0.459 total
grep -Pv '(.).*\1' > q  0.40s user 0.00s system 87% cpu 0.464 total

のように断然速くなる。

参考にperlとrubyの解。例によってまったく同じ。

% time seq 1234567 7654321 | perl -ne 'print unless /[890]/ || /(.).*\1/' >q 
seq 1234567 7654321  0.13s user 0.14s system 10% cpu 2.500 total
perl -ne 'print unless /[890]/ || /(.).*\1/' > q  2.49s user 0.01s system 99% cpu 2.503 total
% time seq 1234567 7654321 | ruby -ne 'print unless /[890]/ || /(.).*\1/' >q
seq 1234567 7654321  0.21s user 0.08s system 6% cpu 4.817 total
ruby -ne 'print unless /[890]/ || /(.).*\1/' > q  4.80s user 0.02s system 99% cpu 4.825 total
でも、やっぱ下記の愚直な方法のわかりやすさにはなんか敵わないような。
% time seq 1234567 7654321 | awk '/1/&&/2/&&/3/&&/4/&&/5/&&/6/&&/7/' > q
seq 1234567 7654321  0.19s user 0.06s system 18% cpu 1.408 total
awk '/1/&&/2/&&/3/&&/4/&&/5/&&/6/&&/7/' > q  1.39s user 0.01s system 98% cpu 1.416 total
% time seq 1234567 7654321 | grep 1 | grep 2 | grep 3 | grep 4 | grep 5 | grep 6 | grep 7 > q
seq 1234567 7654321  0.14s user 0.02s system 20% cpu 0.743 total
grep 1  0.71s user 0.02s system 98% cpu 0.742 total
grep 2  0.41s user 0.01s system 56% cpu 0.739 total
grep 3  0.23s user 0.02s system 33% cpu 0.736 total
grep 4  0.10s user 0.00s system 13% cpu 0.733 total
grep 5  0.04s user 0.00s system 4% cpu 0.730 total
grep 6  0.01s user 0.00s system 1% cpu 0.727 total
grep 7 > q  0.00s user 0.00s system 0% cpu 0.725 total

2016-09-04 (Sun)

Q8-2 2011年日本数学オリンピック予選第3問改題 #シェル芸

8-1の結果を使ってもいいと書いてあるが、実は使わないほうが簡単。
まず、素数ということは計算結果は奇数にならないといけない。 a*b*c*d + e*f*gのように2つグループに分けるときに、
両グループに偶数が分かれると結果は偶数になってしまう。
つまり2,4,6は同じグループになければいけない。
さらに3,6も分かれると結果は3の倍数になってしまうので同じグループにする必要がある。
つまり 2*3*4*6 + 1*5*7 しかない。
結果は179で素数。
とまあ、これで解けてしまうわけだ。
あとは組み合わせ。

% echo $[2*3*4*6 + 1*5*7] | factor
179: 179
% printf "%s\n" {2,3,4,6}{2,3,4,6}{2,3,4,6}{2,3,4,6}+{1,5,7}{1,5,7}{1,5,7} | grep -Pv '(.).*\1' | head
2346+157
2346+175
2346+517
2346+571
2346+715
2346+751
2364+157
2364+175
2364+517
2364+571
% printf "%s\n" {2,3,4,6}{2,3,4,6}{2,3,4,6}{2,3,4,6}+{1,5,7}{1,5,7}{1,5,7} | grep -Pv '(.).*\1' | wc -l
144
% echo $[4*3*2*1 * 3*2*1]
144

全部で144個。

8-1の結果を使う方法もついでに。
「その時のa〜gの数字を全て求めましょう」とあるのでfactorを使うのはあまりいい方法じゃない。
素数かどうかの判断は愚直に余りを求めればいいので結構簡単。
桁数もそれほどじゃないのでエラトステネスのふるいとか考えなくてもok。

% awk -F "" '{for(r=s=a=$1*$2*$3*$4+$5*$6*$7;s%--r;);if(r<2)print $0, a}' tmp | head
2346157 179
2346175 179
2346517 179
2346571 179
2346715 179
2346751 179
2364157 179
2364175 179
2364517 179
2364571 179
% awk -F "" '{for(r=s=a=$1*$2*$3*$4+$5*$6*$7;s%--r;);if(r<2)print $0, a}' tmp | wc -l
144

自分自身よりも小さい整数を順々に試して、1まで行ったら素数決定。


2016-09-05 (Mon)

Perlの呪文 #perlgolf

Q2へのへのもへじのuniqでのPerlの解の解説。日本語である必要もないのでababcadで。

% echo ababcad | perl -pe 's/./$&x~$`!~~$&/ge'                               
abcd

eなのでevalしてるわけでこの部分の呪文をばらして、わかりやすく別名にして()で囲む。

s/./$MATCH x (~$PREMATCH !~ ~$MATCH)/ge

まずは()の中の~を除外して考える。

$PREMATCH !~ $MATCH

これは先行する部分にマッチした文字がなければ1になることを意味する。
その場合は$MATCH x 1でそのまま残る。
マッチした場合は0になり$MATCH x 0でその文字は消える。
以上によりuniq処理となる。

では~はなんのためという話になるが、!~は正規表現というところがミソで、
$MATCHにメタ文字が含まれていた場合を考えるとまずいとわかる。

% echo abab.cad | perl -MEnglish -pe 's/./$MATCH x ($PREMATCH !~ $MATCH)/ge' 
abcd

のように.はワイルドカードなのでどんな文字にもマッチして消えてしまう。
これを防ぐにはescapeしてやる必要がある。

% echo abab.cad | perl -MEnglish -pe 's/./$MATCH x ($PREMATCH !~ quotemeta $MATCH)/ge'
ab.cd

という処理をゴルフすると~を使う方法になる。
~でビット反転するとメタ文字には絶対にならないので、quotemetaの代わりに使える。
よくこんな方法を思い付くよな。

% echo abab.cad | perl -MEnglish -pe 's/./$MATCH x (~$PREMATCH !~ ~$MATCH)/ge'
ab.cd

というわけでへのへのもへじの場合は~がなくてもいい。


2016-09-06 (Tue)

GNU findのprintf

findしてlsってなんか二度手間っぽいので、GNU findを使っているなら-printfオプションがお勧め。

% find typhoon -type f -printf "%CF %CT %p\n" | sort | head
2016-09-01 16:19:36.6287212150 typhoon/japan_near_2016-09-01-09-00-00-large.jpg
2016-09-01 16:19:36.9047139800 typhoon/japan_near_2016-09-01-12-00-00-large.jpg
2016-09-01 16:19:37.1567073750 typhoon/japan_near_2016-09-01-15-00-00-large.jpg
2016-09-02 07:13:13.6201514790 typhoon/japan_near_2016-09-01-18-00-00-large.jpg
2016-09-02 07:13:13.9401440760 typhoon/japan_near_2016-09-01-21-00-00-large.jpg
2016-09-02 07:13:14.0801408380 typhoon/japan_near_2016-09-01-22-00-00-large.jpg
2016-09-02 07:13:14.1561390800 typhoon/japan_near_2016-09-01-23-00-00-large.jpg
2016-09-02 07:13:25.4878769220 typhoon/japan_near_2016-09-02-01-00-00-large.jpg
2016-09-02 07:13:25.5878746080 typhoon/japan_near_2016-09-02-02-00-00-large.jpg
2016-09-02 07:13:25.7158716460 typhoon/japan_near_2016-09-02-03-00-00-large.jpg

2016-09-07 (Wed)

なぜかdiigoのアカウントが消えた

2,3日経つがやはり復活してないので新たに別名アカウントで作った。
たぶん登録したアイテム数は10万を越えていたと思われるが、
もやは既読フラグとしてしか使ってないので過去はなくてもどうでもいいのであった。


2016-09-10 (Sat)

Sony Reader PRS-T1のアップデート

自分で作ったEPUB3の文書をPRS-T1で見るとなぜかページ単位が1,1-2,2とか
わけのわからない表示になって気持ち悪かったんだけど、
全然本体のアップデートもしてないし確認したらどうもそれらしいアップデート内容が。
「EPUB3形式の書籍の表示品質を改善しました。」これは期待できる。
T3と違って専用のツールを使わないとアップデートできないもんだから気づかなかったが、
2年も前にすでに存在していた。適用したら解消した。なんでもっと早く確認しなかったのか。


<Older(,) | Newer(.)> | Recent(/)>> | RDF


WWW を検索 jarp.does.notwork.org を検索

わたなべひろふみ
Key fingerprint = C456 1350 085F A320 C6C8 8A36 0F15 9B2E EB12 3885
Valid HTML 4.01!