Pythonひよっこが『 言語処理100本ノック 2020 』に挑戦【17-19】

Pythonひよっこのわたしが、『言語処理100本ノック 2020』の第2章の17-19に挑戦してみました。
どのコードも長くなってしまったので、今回は三つだけにしました。
わたしが作った解答と一般の方が公開されている解答と比べながら、1問ずつ学んだことなどをまとめていきたいと思います。

こちらの続きになります
[Pythonひよっこが『言語処理100本ノック 2020』に挑戦【15・16】](https://qiita.com/tulip_rabbit/items/7766dec6bbb4cfea4553)

#第2章:UNIXコマンド
*基本的に、ファイルは最初に指定されている"popular-names.txt"を使用しています。(12.や17.みたいに、例外もあります)

##17.１列目の文字列の異なり
```python
#17.
f=open("popular-names_11.txt",'r')
text=f.readlines()
ans=set()

for i in range(len(text)):
    text_new=text[i].split(" ")
    ans.add(text_new[0])
    
print(ans)
print(len(ans))
f.close()
```

11.で作った、タブをスペースに変換している方のファイルを使いました。
ansの要素数を確認したら、136こになっていました。
ちゃんと重複がはじかれたみたいです。


ターミナルで cut/sort/uniqコマンドを使って確認します。

```
cut -f 1 -d " " popular-names_11.txt | sort | uniq  
```

念のため、行数も確認すると...

```
cut -f 1 -d " " popular-names_11.txt | sort | uniq | wc -l
     136
```
136行になっていました！ちゃんとpythonのコードと同じ結果になっていました。
はじめてコマンドを並べる方法を学びました。便利ですね！

この問題では、はじめてセットを利用しました。
セットは要素を格納するデータ型ですが、
　・要素に順番がない
　・重複した要素を含まない
という特徴があります。
座学で勉強していたときは セットなんていつ使うんだろう...？ と思っていたのですが、重複を許したくないときに使うと便利ですね。勉強になりました。

また、12.と13.で引っかかっていた、for文のrange()もlen(text)でうまくいくことを思いついたので実装してみました。
前の自分が持っていた疑問が、自分で解決できたのは大きな収穫でした。


##18.各行を3コラム目の数値の降順にソート
```python
#18.
##xが3列目のソートされたリストのどこに入るのかを返す
def where(num_list,x):
    num_list.append(x)
    num_list.sort(reverse=True)
    return num_list.index(x) 


f=open("popular-names.txt",'r')
text=f.readlines()
ans=[]
num_list=[]

##場所を探してans[]に入れる
for i in range(len(text)):
    text_new=text[i].split("\t")
    ans.insert(where(num_list,int(text_new[2])), text[i])

##結果の出力
for i in range(len(text)):
    print(ans[i],end="")

f.close()
```
悩みました...実装の方向性もそうだし、いろいろと複雑になってしまいました(><)
流れとしては、
　・1行目から順番に見ていって、
　・i行目までの、3列目の値を降順に並べ替える @ where関数
→元々あったソートしているnum_listにx(=(i,3)の値)を加えて、ソートし直す 
　・xがnum_sortのどこに入ったかを返す
→where関数の返り値になる
　・where関数の返り値のところにi行目のテキストを挿入する
を繰り返しています。

前に学んだ、『改行しないでprint()する』を実装できました！


ターミナルにて、sortコマンドを使って確認します。

```
sort -n -k 3 -r popular-names.txt
```

同じように、逆順に出力することができていました。
-n は数値としてソートするオプション、-r は降順にソートするオプションです。

##19.各行の1コラム目の文字列の出現頻度を求め，出現頻度の高い順に並べる
```python
#19.

##キー:名前、値:出てきた回数
f=open("popular-names.txt",'r')
dic_col1={}

for line in f:
    line=line.split("\t")
    word=line[0]
    
    ##ディクショナリ deic_col1 に入れる
    ##すでにwordがdic_col1にあるとき→itemを1増やす
    if word in dic_col1:
        dic_col1[word]+=1
    else:
        dic_col1[word]=1

##出力
for num,word in sorted(dic_col1.items(),reverse=True,key=lambda x:x[1]):
    print("%r\t%r" % (word,num))

f.close()
```
前に似たようなコードを書いたことがあったので、そのまま利用しました。
ディクショナリdeic_col1を作成し、一致するキーがすでに存在すれば値を1増やす、存在しなければ値を1にして新しく追加する...をくり返します。

ターミナルで確認します。

```
cut -f 1 -d " " popular-names_11.txt | sort | uniq -c | sort -r
```
これで、コードとほとんど同じものが出力されました。異なるのは、出現回数が同じものの順番だけです。
UNIXコマンドは、
　1.cutコマンドで1列目だけ抜き出す
　2.sortで名前が同じものが連続に並ぶようにする
　3.uniqコマンドで重複を消し、オプション -c で重複した個数を先頭につける
　4.sortコマンドで先頭の数字でソート、オプション -r で降順にならぶ
という構造です。

#第2章のまとめと反省
UNIXコマンド、便利！！
大規模なデータを扱うときによく利用するんだろうな〜って思いました。

UNIXコマンドは今まで使ったことがなかったので調べながら進めていきましたが、最後の方はオプションや組み合わせて使用するなど、使いこなせるようになってきました。
コードも構造が複雑になってきていて、理解の足りないところ(リストとか文字列とかの処理)でつまずくようになってきました。

#これから
3章をのぞき見してきましたが、なんかまったく聞いたことのない単語が並んでいて戦々恐々しています...
どこまで自力で進められるか分かりませんが、できるところまでまったりと取り組んでいこうと思います。