【問題と解答】jus共催 第46回人類はおそらくシェル芸に仕事を奪われるか奪われないかのどちらかであるシェル芸勉強会

Sat Feb 15 16:53:29 JST 2020 (modified: Sat Feb 15 16:53:29 JST 2020)
views: 1845, keywords:プログラミング,勉強会,シェル芸,シェル芸勉強会 この記事は最終更新日が4年以上前のものです。

  • 問題で使われているデータファイルはGitHubにあります。クローンは以下のようにお願いします。
$ git clone https://github.com/ryuichiueda/ShellGeiData.git

Q1

 次のようなデータがあります。

$ cat data 
   32 -12 42 -4 3 34 32 9 22 24 25 19 18 -14 -4

これを、次のように1列目に十の位、2列目に一の位の数を並べた表現(幹葉表示)に変換してください。

-0 44
    0 39
    4 2
   -1 24
    3 224
    2 245
    1 89

解答例

$ cat data | tr ' ' \\n | sed 's/.$/ &/' | awk 'NF==1{print 0,$1}NF!=1' 
   | sed 's/^- /-0 /' | sort -n 
   | awk '{a[$1]=a[$1]$2}END{for(k in a)print k,a[k]}' | sed 's/^. / &/'
   -0 44
    0 39
    4 2
   -1 24
    3 224
    2 245
    1 89

Q2

 次のdata2は、1列目のデータに対して2列目にチェック用のビットを書き込んであるファイルです。 2列目の左右のビットがそれぞれ1列目の0と1の数の偶奇を表しており、 偶数なら0、奇数なら1になっています。1列目と2列目の整合性がとれていない行の番号を出力してください。

$ cat data2
   0101010110101010101101010101101010101 10
   0100000000010101010110101010101011101010 11
   101011010101011010101010101010101010100101 00
   010110101010111111111110101010101110 01
   011010101010110101010101010101010 01

解答例

$ cat data2 | awk '{print gsub(/0/,"",$1)%2 gsub(/1/,"",$1)%2,$2}' | awk '$1!=$2{print NR}'
   4

Q3

 次のファイルについて、1〜3列目の3行、4〜6列目の3行をそれぞれ3x3行列とみなして掛け算してください。

$ cat matrix
   3 4 -2 1 -9 4
   3 -1 2 3 -2 -8
   2 5 6 0 2 -3

解答例

$ awk 'NR<4{for(i=1;i<=3;i++)a[NR][i]=$(i+3)}NR>=4{for(i=1;i<=3;i++)
   {printf("%d ",$1*a[1][i] + $2*a[2][i] + $3*a[3][i])}print ""}' matrix matrix 
   15 -39 -14 
   0 -21 14 
   17 -16 -50 

Q4

 A, B, C, Dの4種類の文字を2つにグループ分けするときの全通りのパターンを列挙してください。各グループかならず一つの文字が入っている(空集合を認めない)こととします。

解答例

$ echo {A..D}{A..D}{A..D}{A..D} | tr ' ' \\n | grep -Ev '(.).*\1' 
   | awk '{for(i=1;i<4;i++){print substr($1,1,i), substr($1,i+1)}}' | tr ' ' \\n 
   | awk 'BEGIN{a[1]="A";a[2]="B";a[3]="C";a[4]="D"}{for(i=1;i<=4;i++)if(index($1,a[i])){printf a[i]}print ""}' 
   | xargs -n 2 | sort -u | awk '{print ($1~/A/) ? $1" "$2 : $2" "$1}' | sort -u
   A BCD
   AB CD
   ABC D
   ABD C
   AC BD
   ACD B
   AD BC
   $ echo {A..D}{A..D}{A..D}{A..D} | tr ' ' \\n | grep -Ev '(.).*\1' 
   | awk '{for(i=1;i<4;i++){print substr($1,1,i), substr($1,i+1)}}' 
   | opy '["".join(sorted(x)) for x in F[1:]]' | opy '[sorted(F[1:])]' | sort -u
   ['A', 'BCD']
   ['AB', 'CD']
   ['ABC', 'D']
   ['ABD', 'C']
   ['AC', 'BD']
   ['ACD', 'B']
   ['AD', 'BC']

Q5

 次のような出力(パスカルの三角形)を得てください。完全に左右対称である必要はありませんが、なるべく左右対称にしてください。

            1
              1 1
             1 2 1
            1 3 3 1
           1 4 6 4 1
         1 5 10 10 5 1
        1 6 15 20 15 6 1
      1 7 21 35 35 21 7 1
     1 8 28 56 70 56 28 8 1
   1 9 36 84 126 126 84 36 9 1

解答例

$ n="0 1 0" ; for i in {1..10} ; do echo $n ;
   n="0 "$(awk '{for(i=1;i<=NF-1;i++)printf $i+$(i+1)" "; print ""}' <<< $n)" 0 " ;
   done | sed 's/^0 //;s/ 0$//' | tac 
   | awk 'NR==1{a=length($0)}{d=(a-length($0))/2;for(i=1;i<d;i++)printf " ";print}' | tac
               1
              1 1
             1 2 1
            1 3 3 1
           1 4 6 4 1
         1 5 10 10 5 1
        1 6 15 20 15 6 1
      1 7 21 35 35 21 7 1
     1 8 28 56 70 56 28 8 1
   1 9 36 84 126 126 84 36 9 1

Q6

 次のファイル内のそれぞれ数字について、上の桁の数からそれぞれ10, 9, 8, ..., 1をかけて総和を求めましょう。例えば4065170060なら、4*10 + 0*9 + 6*8 + ... + 0*1を計算してください。さらに、それぞれの行で求めた数について、最大公約数を求めてください。

$ cat isbn
   4065170060
   4774173444
   4822239292
   4048930699
   4839952981
   4839924015

解答例

### 総和 ###
   $ cat isbn | rev | awk -F "" '{for(i=1;i<=NF;i++)a+=$i*i;print a;a=0}'
   176
   264
   231
   242
   330
   286
   ### 最大公約数 ###
   $ cat isbn | rev | sed 's/./& /g' 
   | awk '{for(i=1;i<=NF;i++)a+=$i*i;print a;a=0}' 
   | python3 -c 'import sys;import numpy as np;a=[int(x) for x in sys.stdin];print(np.gcd.reduce(a))'
   11

Q7

 41人を円形に並べ、1, 2, 3, 4, ..., 41番と番号をつけます。そして、生き残っている3人ごと(最初は3番, 6番, 9番, ...)の順に殺していきます。最後に残る二人は何番になるか、ワンライナーで答えてください。(ヨセフスの問題)

解答例

$ echo {1..41} | awk '{for(i=1;i<=3*39;i+=3){$(NF+1)=$i;$(NF+1)=$(i+1);print}}' | tail -n 1 | awk '{print $(NF-1),$NF}'
   16 31

Q8

 SEND + MORE = MONEYの各アルファベットに0から9の数字1字を割り当てて足し算を完成させてください。異なるアルファベッドには異なる数字を割り当ててください。SMには0を割り当てないでください。答えが分かるものであれば出力はなんでも構いません。

解答例

$ seq -w 90123456 99999999 | grep '^....1' | grep -vE '(.).*\1' | awk -F "" '{print $1$2$3$4,$5$6$7$2,$5$6$3$2$8}' | awk '$1+$2==$3'
   9567 1085 10652
   ### ベタにやった場合 ###
   $ time seq -w 10234567 99999999 | grep -Ev '(.).*\1' | awk -F "" '{print $1$2$3$4,$5$6$7$2,$5$6$3$2$8}' | grep -v '^0' | grep -v ' 0' | awk '$1+$2==$3'
   9567 1085 10652

   real    3m27.610s
   user    4m11.102s
   sys 0m0.662s
   ### grepを分散させるとCPUが多い場合は速くなる ###
   $ time seq -w 10234567 99999999 | grep -Ev '(.)\1' | grep -Ev '(.).\1' | grep -Ev '(.)..+\1' | awk -F "" '{print $1$2$3$4,$5$6$7$2,$5$6$3$2$8}' | grep -v '^0' | grep -v ' 0' | awk '$1+$2==$3'
   9567 1085 10652

   real    2m26.417s
   user    6m13.170s
   sys 0m2.952s
ノート   このエントリーをはてなブックマークに追加 
 

prev:【問題】jus共催 第46回人類はおそらくシェル芸に仕事を奪われるか奪われないかのどちらかであるシェル芸勉強会 next:jus共催 第46回シェル芸勉強会リンク集

やり散らかし一覧

記事いろいろ