Just another Ruby porter,

〜2014年7月中旬〜


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

2014-07-11 (Fri)

trで文字列の繰り返し

aからmを0へ、nからzを1へ変換したいとする。
trでやるならこんな感じになる。

% bash -c 'echo {a..z}' | tr a-z 00000000000001
0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1

足りない分は最後の文字が使われるので、
1はまあそれでいいんだけど、0を何とかしたい。

% bash -c 'echo {a..z}' | tr a-m 0 | tr n-z 1  
0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1

2回に分けるのはわかりやすいが、man trしてみたら

       [CHAR*REPEAT]
              REPEAT copies of CHAR, REPEAT octal if starting with 0

という記述を発見。つまり

% bash -c 'echo {a..z}' | tr a-z '[0*13]1'              
0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1

と書けるわけだ。


2014-07-12 (Sat)

Coffee Time Challenges

おいらもやってみた。1問目。

1) Two Bases
Challenge: Find three digits X, Y and Z such that XYZ in base10 (ten) is equal to ZYX in base9 (nine)?

% for i in {1..8}{1..8}{1..8};do [ $[9#$i] = `rev<<<$i` ] && rev<<<$i; done
445

bashとzshならいける。ああ、でも9進数の連番ならこれでいいのか。

% printf "%s\n" {0..8}{0..8}{0..8}|rev|nl -v0|awk '$1==$2""&&$0=$1'
445

9進数の方をreverseしてnl -v0で0からの行番号をつけることで10進数へ変換の代わり、
あとは同じものを表示すればいい。


2014-07-13 (Sun)

2) One Million

2問目。

2) One Million
Challenge: Write 1,000,000 as the product of two numbers; neither of which contains any zeroes.

英語だとなんか意味がよくわからないがつまりこういうことか。

% m=1000000;n=$m;while ((m == m/n*n));do : $[n/=2];done; echo $[n*2], $[m/n/2] 
15624, 64

tailsさんからご指摘いただいたので修正。

% m=1000000;n=$m;while ((m == m/n*n));do : ${l=n} $[n/=2];done; echo $l, $[m/l] 
15625, 64

1) Two Basesふたたび

1問目の9進数は10進の連番から9がつくのを消してもいける。
あとnl使わんでも最終的にはawkなんだからNRを使えばいいだけだった。

% seq -f '%03g' 888 | sed '/9/d' | rev | awk 'NR==$1""&&$0=NR'
445

2014-07-14 (Mon)

3) High Product

Challenge: Use the digits 0-9 to create two numbers. What is the highest
product you can achieve when these two numbers are multiplied together?

なんかチートっぽいが、候補となる組み合わせをとりあえず重複ありで表示し、
grepで重複を消して、bcで計算してsortして一番でかいのを取り出してできあがり。

% printf "%s\n" 8{7,6}{5,4}{3,2}{1,0}\*9{7,6}{5,4}{3,2}{1,0} | \
  grep -v '\(.\).*\1' | sed 's/.*/print "&=";&/' | bc | sort -s -t= -k2,2n | tail -1
87531*96420=8439739020

2014-07-15 (Tue)

4) Exactly a third

Challenge: Arrange the numerals 1-9 into a single fraction that equals exactly
1/3 (one third). No other math symbols wanted; just concatenation some digits
for the numerator, and some to make a denominator.

1から9までの数字を1回だけ使って1/3にする。
9個ということは必然的に4桁と5桁に分割される。
4桁のほうは3倍して桁が上がるのだから3334以上。
1回しか使わないので3456以上。同じように9876以下。
この範囲で見つければいい。
awkで3倍したものと一緒に表示し、grepで重複しているものを除く。
ついでにここで0も除外。うまい具合にはまった。

% seq 3456 9876 | awk '{print $1 "/" ($1*3)}' | grep -v '\(.\).*\1\|0'
5823/17469
5832/17496

2014-07-16 (Wed)

10000列のawk

問題の作成を

% seq 10000 | paste -sd,

としていたが、pasteは不要で

% seq -s, 10000

でいいのであった。

というわけでawkでの解はこんな感じ。

% seq -s, 10000 | awk 'ORS=NR%100?RS:"\n"' RS=,

しかし

% seq -s, 10000 | sed 's/,/\n/100;P;D'

の解には敵わないな。余計な改行もつかないし。


2014-07-17 (Thu)

余計な改行をなんとかする

10000列で100行100列じゃわかりにくいので、100列を10行10列で。

% seq -s, 100 | awk 'ORS=NR%10?RS:"\n"' RS=,       
1,2,3,4,5,6,7,8,9,10
11,12,13,14,15,16,17,18,19,20
21,22,23,24,25,26,27,28,29,30
31,32,33,34,35,36,37,38,39,40
41,42,43,44,45,46,47,48,49,50
51,52,53,54,55,56,57,58,59,60
61,62,63,64,65,66,67,68,69,70
71,72,73,74,75,76,77,78,79,80
81,82,83,84,85,86,87,88,89,90
91,92,93,94,95,96,97,98,99,100

最後に余計な空行が入ってしまう。
RS=,にしているので最後の改行がそのまま出てきているわけだ。
単に消すだけならsubを使えばいいが、それもねえ。

そんな難しく考えるまでもなくRSに改行も加えてしまえばいい。

% seq -s, 100 | awk 'ORS=NR%10?",":"\n"' RS='[,\n]' 
1,2,3,4,5,6,7,8,9,10
11,12,13,14,15,16,17,18,19,20
21,22,23,24,25,26,27,28,29,30
31,32,33,34,35,36,37,38,39,40
41,42,43,44,45,46,47,48,49,50
51,52,53,54,55,56,57,58,59,60
61,62,63,64,65,66,67,68,69,70
71,72,73,74,75,76,77,78,79,80
81,82,83,84,85,86,87,88,89,90
91,92,93,94,95,96,97,98,99,100

RSが","じゃなくなったので、ORSへは文字列","で。


2014-07-18 (Fri)

6) Word Doc

5)は一体なんなんだろうねえ。引っ掛けかと思った。

というわけで6)のWord Doc。

Challenge: I open up a Word document and type all the numbers 1-10000, separated by spaces, (I did not use any 'thousands' punctuation; just raw numbers). Then, my daughter came along and used search and replace, and changed all the digits '0' into spaces. If I now sum up all the numbers in the document what is the total? (Any number delineated by one or more spaces is a distinct number).

Ubuntuにはnum-utilsというパッケージがあって、
それに含まれるnumsumコマンドを使うと簡単。

% seq -s " " 10000 | tr 0 " " | numsum -r
37359001

trで空白を+にしてbcに食わせるとか、awkで処理するのが一般的だけど、
こんなコマンドもあるということで。

% numsum -h
---------------------------------------------------------------------------
numsum :  A program that adds up all numbers of input and returns the sum.
---------------------------------------------------------------------------
Usage:
        numsum [options] <file>   (Input from a file.)
        | numsum [options]        (Input from command pipeline.)
        numsum [options]          (Input on STDIN.  Use Ctrl-D to stop.)

Options:
        -i      Only return the integer portion of the final sum.
        -I      Only return the decimal portion of the final sum

        -c      Print out the sum of each column.
        -r      Print out the sum of each row.

        -x <n>  Specify a comma seperated list of columns to print.
        -y <n>  Specify a comma seperated list of rows to print.

        -s <string> Specify a seperator string for spliting columns.
                    This defaults to consecutive whitespace.

        -d      Debug. For developers only.
        -h      Help: You're looking at it.
        -V      Increase verbosity.
        -q      Quiet mode, don't print any warnings.

2014-07-19 (Sat)

6) Word Doc をbashで

なんとなく全部bashで解いてみたらいけた。

% bash -c 'a=({1..10000}); a=${a[@]//0/ }; echo $[${a// /+}]'
37359001

と思ったが、これだと1から10000までを空白区切りになってないとか、
0の繰り返しも1個の空白になるんで題意と違ってしまう。

% bash -c 'a=({1..10000}); a="${a[*]}"; a="${a//0/ }"; echo $[${a// /+}0]'
37359001

こうか。しかしbashも地味に変な機能があるな。

zshは

% zsh -c 'echo $[1++1]'         
zsh:1: bad math expression: operator expected at `1'

となってしまうので+の繰り返しを1個の+へ変換するなりしないといけない。

最初の例は

a = [*"1".."10000"]
a = a.map{|x|x.tr("0", " ")}.join(" ").sub(/ +$/, "")
puts eval a.tr(" ", "+")

と同じはずだが、あまりに深すぎてstack level too deep (SystemStackError)で、
Rubyが落ちてしまう。


2014-07-20 (Sun)

bashで間接的な変数参照

zshでいうところの

% zsh -c 'foo=bar; bar=1; echo ${(P)foo}'
1

という機能はbashじゃevalとかしないと無理だと思っていたら、

% bash -c 'foo=bar; bar=1; echo ${!foo}'  
1

でできると知った。

parameter の最初の文字が感嘆符ならば、変数間接展開が行われます。 bash は残りの
parameter からなる変数の値を変数の名前と見なします。
そしてそこで得られた名前の変数を展開した値を、置換処理の続きで使います。 これが
間接展開 です。

<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!