studies

いろいろ勉強用備忘録的な感じ

京都に行ってきた【東寺・来迎院・宝泉院】

仕事が閑散期なため、ふと思いついて京都に行ってきた。
そうだ、京都行こう。

東寺教王護国寺ともいう。
真言宗のお寺。五重塔の初層が公開されていた。
f:id:developingskills1110:20170114231604j:plain:w300

ところ変わって大原来迎院。
大原エリアではここだけまだ来たことがなかった。
ここは天台宗のお寺。静かで良い。
f:id:developingskills1110:20170114231740j:plain:h300

こちらは宝泉院。ここは3回目かな。
f:id:developingskills1110:20170114231953j:plain:h300

宝泉院は一名を額縁の庭園といい、京都でも屈指の美意識を感じさせる。
今日は額縁の向こうは吹雪いていた。
f:id:developingskills1110:20170114232317j:plain:h300

勉強用サーバ兼ファイルサーバの構築(samba/Ubuntu16.04/Windows10)

思ったより簡単にできてしまったのでメモ。

機材

小さなノートPC(1kg以下。使いやすい。HDD容量30GBくらい)
大きなノートPC(重い。使いづらい。HDD容量500GBくらい)

今までの環境

どっちもOSはWindows10。
小さな方にMS-Officeを入れてexcelで遊んだり、2chみたり、YouTubeみたり。
大きな方にVirtualBox上にUbuntu16.04を入れて、PerlとかC++とかで戯れる。

問題点

「勉強するぞ」ってならないと勉強しない。
Linux上で勉強しててかつexcel使いたいときに、PCを行き来する必要。
VirtualBoxがもっさりしててイライラする。

解決策

勉強って言っても基本コマンドラインしか使わないし、大きなPCをサーバにして、小さな方からsshでログインすればOK。
ついでにファイルも共有できる感じにすれば楽しそう。

Ubuntu16.04をインストール(サーバ側)

DVDに焼いて、普通にインストールするだけと思いきや。
デフォルトで「Windows Boot Managerとは別にインストール」という選択肢があり、これでデュアルブートになるらしい。
あまり前の環境に未練はないけど、せっかくなのでデュアルブートにしてみた。

TeraTermssh接続(クライアント側)

サーバ側のIPアドレスを入力して、ユーザ名・パスワードを入力して接続する。
難なく接続できた。素晴らしい。

sambaのインストール・設定(サーバ側)

このままTeraTermで全部操作してしまってもOK。
sambaをインストール。

sudo apt-get install -y samba

ログインユーザを追加。

sudo pdbedit -a [追加するユーザ名]

sambaの設定ファイルを編集。

sudo vim /etc/samba/smb.conf

須藤さんに登場してもらわないと、編集できません。
[homes]の下がコメントアウトされているので、有効にする。
readonly属性はnoにしておく。
これでクライアント側からログインすると、/home/[ユーザ名]の下を見られるようになるっぽい。
readonly属性がyesだと見られるだけだね(書き込めない)。

vimを閉じたら、sambaを再起動。

sudo systemctl restart smbd nmbd

クライアント側からディレクトリを見る。

エクスプローラでネットワークを見ると、サーバのPC名が表示されているので、ダブルクリックしてログインする。
あるいは、\\[IPアドレス]と直打ちしてログインしてもOK。

ついでにiPhoneからも…

もちろんiPhoneからも見れるはずなので試してみた。
「File Explorer」というアプリをインストールして、ログインすると中身が見える。

感想

あまりに簡単だったので拍子抜けした。
クライアントサーバシステムとか名前からして凄そうだし、敬遠していた。
まだ分からないけど、捗りそう。
活用していこう。

2017年の目論見

あけましておめでとう。

年は明けて2017年。
今年もよろしくお願いします。

年頭よろしく、今後の目論見なんかを作ってみる。

ブログの更新頻度向上

アウトプットの場としてのブログの利用価値を見直す。

応用情報技術者

4月の試験はこれ。

ネットワークスペシャリスト

10月の試験はこれかな。
正直ネットワークにはあまり興味がないのが辛いところ。
でもネットワーク知らないと、環境構築とかできないし。
マスタリングTCP/IP 入門編 第5版

アルゴリズム

どうも基本的なアルゴリズムを知らないような気がしている。
アルゴリズムクイックリファレンス 第2版

機械学習

最近はやり。
やっぱりちょっと興味持っちゃうよね。
ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装

Python

はやりのスクリプト言語
機械学習の本なんかはこれで書かれていることが多いし、必要になるかなと。
入門 Python 3

Haskell

純粋関数型言語
需要は少ないだろうけど、理論的な側面に惹かれている。
すごいHaskellたのしく学ぼう!

C++

結局かじっただけになっているオブジェクト指向言語
たぶん今後も仕事で付き合うことになる。
プログラミング言語C++第4版 Effective C++ 第3版 (ADDISON-WESLEY PROFESSIONAL COMPUTI) Effective Modern C++ ―C++11/14プログラムを進化させる42項目

コンピュータアーキテクチャ

基本だけど、表面的にしか理解していないことが多い分野という感じ。
今年の終わりには「実感」を持てるようになりたい。
コンピュータシステムの理論と実装 ―モダンなコンピュータの作り方 コンピュータの構成と設計 第5版 上 コンピュータの構成と設計 第5版 下

Linux

Linuxは今後も仕事で使うことになる。
今のところは「操作」がそれなりにできる段階。
カーネルに足を突っ込む。


盛沢山すぎる気もするけど、知らないことが多すぎるから、これくらいがちょうどよいという気もする。
がんばるぞー。

perlで順序を保つグルーピング ~優先度からの解放~

excelでちょっと複雑なソート - studies
perlでちょっと複雑なソート - studies
perlでちょっと複雑なソート2 - studies
perlでちょっと複雑なソート3 - studies
ワンライナーでちょっと複雑なソート - studies

今までタイトルに「ソート」と付けていたように、この問題を「ソート」の問題として解いてきた。
今回は別の視点でこの問題を解いてみよう。

「別の視点で」と書いたが、実は最初からこの問題は必ずしもソートの問題として定義されていたわけではない。
私の書いた問題文はこうだった。

これを、次の条件でソートするのが本日の課題であった。

 1.基本的な順番は変えない。

 2.同じ都道府県どうしをまとめる。

たとえば、上の例のデータでいえば、次のようにソートすることになる。

 1.第4行まではすべて異なる都道府県なので、とりあえずここまでは何もしない。

 2.第1行で京都府京都市がでてきたあと、第5行で京都府宮津市が出てくる。同じ都道府県同士をまとめるので、第1行と第2行との間に、この第5行目のデータを挿入する。

 3.そのあとさらに下を見ていくと、長野県諏訪市が出てくる。このデータを長野県松本市のすぐ下に移動する。

重要なのは2の「同じ都道府県同士をまとめる」というところだ。
つまり、この問題はソートの問題ではなくグルーピングの問題であると考えてもよい。
(正確に言えば、グルーピング+ソートの問題なのだが、どちらに重点を置くか、ということで少し解き方が変わってくるように思う)。

この問題は、グルーピングした結果を表示するときに、元の順序をできるだけ保つようにする、というだけなのだ。
ここでいう「順序を保つ」というのは、最初に出てきたグループを優先し、次にグループ内では最初に出てきたメンバを優先する、ということだ。

これまで、条件1の「基本的な順番は変えない」という点に注目していたが、今回は条件2に着目してみよう。
アルゴリズム的には「たとえば」以下で書かれた方法をほぼそのまま採用する。
このアルゴリズムは優先度を全く使っていないのが特徴だ。
優先度を設定して、その優先度順にソートするというのは、おそらくプログラム的には早いのだが、必ずしも人間にわかりやすいものとは言えない。
今回は、優先度を設定せずに書いたので、直観的なコードになったと思う。

次のようになる。

#! /usr/bin/perl -a

push @groups, $F[1] unless grep {$_ eq $F[1]} @groups;
push @{$members{$F[1]}}, $_;

END {
    print @{$members{$_}} for (@groups);
}

説明する。
最初に@groupsという配列に、第2フィールドの要素(つまり都道府県)をpushしている。
ただし、これを行うのは都道府県が最初に現れた時だけだ。
その判定を、unless grepで行っている。
次に、各都道府県の市区町村(本当は行)を、都道府県から決まる配列にpushしている。
ここで、配列のリファレンスに値を持つハッシュ%membersを使い、それを@でデリファレンスして使っているのがポイント。
リファレンスを使っているのでややこしいが、配列に値を持つハッシュを作っていると思えばOK。
最終的には、こんな感じのハッシュが作られるわけである。

%members = 
(
  京都府 => [ 京都市 京都府, 宮津市 京都府, 宇治市 京都府 ],
  東京都 => [ 千代田区 東京都, 渋谷区 東京都, 新宿区 東京都 ],
  .....
)

そして、groupごとに配列を展開してprintして終わり、というのが上のコードの意図するところである。

下のようにkeys関数でグループを求めたくなるが、「Perlでは、ハッシュの要素の順序が保存されない」(『初めてのPerl』, p142)ため、この方法だと、どの順序でグループが現れるかわからなくなってしまう。この方法は使えない。

#! /usr/bin/perl -a

push @{$members{$F[1]}}, $_;

END {
    print @{$members{$_}} for (keys %members);  # しまった!
}

また、毎回unless grepという条件判定を行うのは重いので、とりあえずpushして、最後に順序を保ちながら重複を取り除く、という考え方もできる。
そのときは、下のように"grep {!$seen{$_}++} @groups"という呪文を唱えることになる。
これは有名なイディオムだが、コード全体の直観性を重視した今回の方針から言えば、ちょっと避けたい書き方ではある。

#! /usr/bin/perl -a

push @groups, $F[1]; 
push @{$members{$F[1]}}, $_;

END {
    print @{$members{$_}} for (grep {!$seen{$_}++} @groups);
}

追記:
unless grepという条件判定が遅いことに対しては、exists関数を使って下のように対処するのが良さそう。
grepの計算時間はO(N)だが、ハッシュを使った下の書き方なら計算時間は定数時間O(1)になるハズ。

#! /usr/bin/perl -a

push @groups, $F[1] unless exists $members{$F[1]};
push @{$members{$F[1]}}, $_;

END {
    print @{$members{$_}} for (@groups);
}

ワンライナーでちょっと複雑なソート

早く目が覚めてしまった。
これは午後眠くなるぞー。

さて、excelperlでいろいろやってきたこの問題。

studies.hatenablog.com

最後の仕上げ?として、perlを使わず、ワンライナーでやってみる。
(もしかしたらまだ続くかも)。

awk '{p[$2] || (p[$2]=NR); print p[$2], $0;}' city.txt | sort -snk1 | sed -E 's/^\S+\s+//'

まず、awk連想配列を使って、優先度を頭につける。
そのあとsortでソート。
sオプションは、安定ソートにするオプション
(デフォルトはおそらくクイックソートで不安定)。
nオプションは、数値としてソートするオプション
(デフォルトは文字列としてソート)。
kオプションは、特定のフィールドをキーにするオプションで、ここでは第1フィールド、つまり、awkで設定した優先度を指定している。
最後にsedで優先度を削除する。
Eオプションは拡張正規表現を使うオプションで、ここでは1回以上の繰り返しを表す量指定子を\+ではなく単に+と書くために指定している。

個人的には、sortコマンドに、こんなにいろいろなオプションがつけられるというのが発見。
perlの宇宙船演算子<=>を使ったソートルールの指定も感心したけれど、sortコマンドでもこんなにいろいろできたとは。

perlでちょっと複雑なソート3

この問題、さらに改良してみる。
studies.hatenablog.com

#! /usr/bin/perl -a
use 5.010;
use sort 'stable';

push @lines, $_;
$priority{$F[1]} //= $.;

END {
    print (sort { 
             $priority{(split /\s+/, $a)[1]} <=> $priority{(split /\s+/, $b)[1]}
           } @lines);
}

awk風のループを仮定する-aオプションをつけて、フィールド変数@Fを使えるようにする。
@Fはawkでいうところの$1,$2,...と同じ(ただし添え字は0始まり)。
これを用いて優先度をハッシュで作成する。
$countの代わりに使っている$.はawkでいうところのNRで、行番号。
メインループで優先度の設定をした後、ENDブロックでソートして出力。

%prefというハッシュは今回は使わず、ソートの際に行そのものからsplitとリストスライスで要素を取り出している。
(ここでも@Fが使えればいいけれど…)。

これはほぼ、excelでやったのと同じアルゴリズムだ。
excelではC2に以下を書いて、これをオートフィル&C列をキーにして並び替えしたのだった。

=iferror(match($b2, $b$1:$b1, 0),  row())

studies.hatenablog.com

もちろんexcelでやったのと比べれば、計算量はだいぶ減っている。

ちなみに、私の環境ではデフォルトで安定ソートの模様なので、実は"use sort 'stable';"のくだりもいらないのではという気もしたが、ちゃんとperldocに以下の記述がある。

The default algorithm is mergesort, which will be stable even if you do not explicitly demand it. But the stability of the default sort is a side-effect that could change in later versions. If stability is important, be sure to say so with a

use sort 'stable';

デフォルトのアルゴリズムマージソートなので、あなたが安定を望んでいることを明示しなくても、安定にソートされる(動くことは動く)。しかし、このデフォルトは後のバージョンで変更になるかもしれない。もし安定性が大切なら、use sort 'stable';と書くこと。

今回は安定性が大切なので、書かなければならない。