青竹雑記帖(6代目)

雑記帖がまた新しくなりました。

くっつけるのは簡単だが、分けるのは難しい(パソコンのデータの話です)

パソコン、プログラミングの題材ばかりでブログ記事が進んでいますが、ここは「雑記帖」ですので、他の題材も当然出る予定です。そろそろ鉄道ネタでいくつか書くつもりです。

さて、タイトル「くっつけるのは簡単だが、分けるのは難しい」ですが、私が研究活動や趣味でデータを扱ってきて何となく感じていたことをようやく言語化したものになります。データ処理をしている人なら一定程度この言明に納得していただけると思います。

データ構造をどうするかというのはシステムを設計する上で一番難しいところで、ここさえ決まればあとはアルゴリズムも決まると言われています。Rob Pike氏のプログラミングの5つの規則 (http://users.ece.utexas.edu/~adnan/pike.html) のうち、ここに述べた規則5を以下に引用し、日本語訳を示します(夜眠くて頭が働かないので機械翻訳で😛)

Rule 5. Data dominates. If you've chosen the right data structures and organized things well, the algorithms will almost always be self-evident. Data structures, not algorithms, are central to programming. (訳: 規則5、データが支配する。適切なデータ構造を選択し、物事をうまく整理していれば、アルゴリズムはほとんど常に自明である。アルゴリズムではなくデータ構造がプログラミングの中心である。)

良いデータ構造であるとさまざまな仕事が捗ります。良くないデータ構造ですと、データから有用な情報を引き出す処理に多くの時間を要し、作業効率が低下してしまいます。その一例として、住所録システムのデータを考えてみたいと思います。住所録に最低限必要なフィールドには名前、住所、電話番号、電子メールアドレスがあります。漢字で書かれた名前であれば読み仮名もあれば便利そうです。住所にはついでに郵便番号も入れてしまいましょう。このとき、データをどう保存するかで、次のような方法が考えられます。

  • 名前
    • 姓・名(さらに広く対応するならミドルネームも)に分ける。
    • 一つのフィールドにする。
  • 住所
    • 郵便番号・都道府県・市区町村・町名・丁目・番地に分ける。
    • 上の項目のいくつかをまとめる。
    • 全部一つのフィールドにする。
  • 電話番号
    • (NTT加入電話の場合)市外局番・市内局番・電話番号に分ける。
    • (携帯電話番号の場合)3桁・4桁・4桁に分ける。
    • 一つのフィールドにして、ハイフン等で区切る。
    • 一つのフィールドに番号10~11桁をそのまま入れる。

実社会で運用されているシステム、たとえば通信販売の住所登録方式はこの中の複数の組み合わせで構築されています。何が最適かはかなり難しく、利用者に入力してもらう際の煩雑さにも関わってきますが、私は「迷ったときは細かく切っておく」という作戦を提唱したいと思います。もちろん区切りは意味のあるまとまりで設定するのが良く、たとえば名前を一文字ずつ切って格納するのは一般的にナンセンスです。(プログラム処理上の内部の取り扱いで一文字ずつに切らざるを得ないのはC言語で見られますが、プログラムの事情をデータ格納のところまで引っ張り出してしまうことにはあまり意味がありません。)

区切ったデータをくっつけるのは簡単です。たとえば ExcelLibreOffice Calc などの表計算ソフトであれば、いくつかのセルに入ったデータや文字列をくっつけてひとつの値にする CONCAT 関数があります。プログラミングの際も、文字列結合の関数や演算子で全部くっつけてしまえます。一方、ひとつにまとまったデータを分けることは難しいです。意味がある単位で区切りが入っていれば、それを頼りに分割できます。多くのプログラミング言語では文字列分割関数(一般には split 関数やメソッド)でサクッと切れますが、ExcelLibreOffice Calc では一筋縄ではいきません。これらには文字列分割関数がありません。文字列検索関数・文字列切り出し関数を駆使して非常に面倒な式を書かねばなりません。ちなみに、Google スプレッドシートでは SPLIT 関数が使えますので楽です。表計算ソフトでも速く実装してくれたまへ。区切りが入っていなければもはや地獄です。住所や電話番号は規則性がある(都道府県は47通りしかない、市区町村は最後に必ず「市・区・町・村」が来る、電話番号は付番規則が定まっている)ため、正規表現を用いるなどしてパターンマッチングにより切り出すことが可能です。でも町名はどうしましょう。番地もスタイルがバラバラですね。お手上げです。正規表現で頑張りすぎると後から保守・改修が難しくなります。この際諦めましょう。

フィールドへのデータ格納法以外にも、たとえばリレーショナルデータベースには「関係の正規化」という手段で関係を適切に定めて、データを分割するような形でいくつかのテーブルに分けて格納し、データを効率的に取り扱うための設計方法論があります。正規化されていくつかのテーブルに分かれたデータはSQLを記述して結合してデータを取り出せます。しかし、ひとつのバカみたいに大きいテーブルに何もかもが詰め込まれてしまうと、データを取り出す方法が非常に限られてしまう恐れがあります。また、もしテーブルを分割することになったとき、そこからデータを欠落・破壊しないように分割することは困難を極めます。不便かもしれませんが、諦めてそのまま運用しましょう。困ったときは必要なデータをSQLで引っ張りだしてCSVでダンプして Excel でコネコネしようか……

困ったときは分けましょう。よいデータ処理ライフを!