夢をかなえるゾウ

なぜこの本を読もうと思ったのかは既に覚えてない。昨年4月に今住んでいるところに引っ越してきて、地元の図書館に最初に貸出予約を入れたのがこの本。既に相当な数の予約が入っていて、今になってようやく借りることができた。

以前に同じ著者の本を読んだことがある。
http://d.hatena.ne.jp/yebihara/20090320/1237565324

正直言って、そっちのほうはイマイチだったが、今回のほうは心に響くところも多くあった。
以下、個人メモ。(と言うか、単なる太字の抜き出し)

  • 靴をみがく
  • コンビニでお釣りを募金する
  • 食事を腹八分目におさえる
  • 人が欲しがっているものを先取りする
  • 会った人を笑わせる
  • トイレ掃除をする
  • まっすぐ帰宅する
  • その日頑張れた自分をホメる
  • 一日何かをやめてみる
  • 決めたことを続けるための環境を作る
  • 毎朝、全身鏡を見て身なりを調える
  • 自分が一番得意なことを人に聞く
  • 自分が一番苦手なことを人に聞く
  • 夢を楽しく想像する
  • 運がよいと口に出して言う
  • ただでもらう
  • 明日の準備をする
  • 身近にいる一番大事な人を喜ばせる
  • 誰か一人の良いところを見つけてホメる
  • 人の長所を盗む
  • 求人情報誌を見る
  • お参りに行く
  • 人気店に入り、人気の理由を観察する
  • プレゼントをして驚かせる
  • やらずにお後悔していることを今日から始める
  • サービスとして夢を語る
  • 人の成功をサポートする
  • 応募する
  • 毎日、感謝する

「お参りに行く」はいい。バカバカしいとか、意味がない、とか言ってやらないやつは、結局そこまでして成功したくないってことだ。その通りだ。

はじめてのRuby

Rubyを勉強しているよ! ifとforと配列とメソッドの書き方を覚えたよ!
週末の新聞にナンバープレース(数独)の問題が載っていたので、それを解くプログラムを書くことにした。お題はこれ。

  5           7  
6     1   2     9
  7 2       6 3  
2 3           1 8
    4 8   7 2    
7       5       3
  6           9  
5   8 3   6 1   7
4     9   8     5

データの持ち方は迷ったが、ひとまず単純に81要素の配列にする。

init = [nil, 5, nil, nil, nil, nil, nil, 7, nil,
        6, nil, nil, 1, nil, 2, nil, nil, 9,
        nil, 7, 2, nil, nil, nil, 6, 3, nil,
        2, 3, nil, nil, nil, nil, nil, 1, 8,
        nil, nil, 4, 8, nil, 7, 2, nil, nil,
        7, nil, nil, nil, 5, nil, nil, nil, 3,
        nil, 6, nil, nil, nil, nil, nil, 9, nil,
        5, nil, 8, 3, nil, 6, 1, nil, 7,
        4, nil, nil, 9, nil, 8, nil, nil, 5]

デバッグしやすいように、配列を9×9で表示するメソッドを書く。

def show_table(data)
  for i in 0..8
    if i == 3 || i == 6 then
      puts " +===+===+===++===+===+===++===+===+===+ "
    else
      puts " +---+---+---++---+---+---++---+---+---+ "
    end

    for j in 0..8
      if j == 3 || j == 6 then
        print " || "
      else
        print " | "
      end

      print data[i * 9 + j] == nil ? " " : data[i * 9 + j]
    end
    puts " |"
  end

  puts " +---+---+---++---+---+---++---+---+---+ "
  puts
end

出力はこんな感じ。(aa記法を使ってもなぜか整形が崩れる・・・)

 +---+---+---++---+---+---++---+---+---+
 |   | 5 |   ||   |   |   ||   | 7 |   |
 +---+---+---++---+---+---++---+---+---+
 | 6 |   |   || 1 |   | 2 ||   |   | 9 |
 +---+---+---++---+---+---++---+---+---+
 |   | 7 | 2 ||   |   |   || 6 | 3 |   |
 +===+===+===++===+===+===++===+===+===+
 | 2 | 3 |   ||   |   |   ||   | 1 | 8 |
 +---+---+---++---+---+---++---+---+---+
 |   |   | 4 || 8 |   | 7 || 2 |   |   |
 +---+---+---++---+---+---++---+---+---+
 | 7 |   |   ||   | 5 |   ||   |   | 3 |
 +===+===+===++===+===+===++===+===+===+
 |   | 6 |   ||   |   |   ||   | 9 |   |
 +---+---+---++---+---+---++---+---+---+
 | 5 |   | 8 || 3 |   | 6 || 1 |   | 7 |
 +---+---+---++---+---+---++---+---+---+
 | 4 |   |   || 9 |   | 8 ||   |   | 5 |
 +---+---+---++---+---+---++---+---+---+

あとは解く。解き方はいくつか考えたが、問題は9×9と限られているので、力づくでバックトラック。

def check_row(table, position, value)
  for i in 0..8
    if table[position / 9 * 9 + i] == value then
      return false
    end
  end

  return true
end

def check_column(table, position, value)
  for i in 0..8
    if table[i * 9 + position % 9] == value then
      return false
    end
  end

  return true
end

def check_block(table, position, value)
  upper_left = position / 27 * 27 + position % 9 / 3 * 3
  for i in 0..8
    if table[upper_left + i / 3 * 9 + i % 3] == value then
      return false
    end
  end

  return true
end

def proceed(init, result, position)
  if position > 80 then
    return true
  end

  if init[position] != nil then
    result[position] = init[position]
    return proceed(init, result, position + 1)
  else
    for i in 1..9
      if check_row(result, position, i) && check_column(result, position, i) && check_block(result, position, i) then
        result[position] = i


        if proceed(init, result, position + 1) then
          return true
        end
      end
    end

    result[position] = nil
    return false
  end
end

show_table(init)

result = []
for i in 0..80
  result[i] = init[i]
end

if proceed(init, result, 0) then
  show_table(result)
else
  puts "no answer"
end

いちおう答えは出る。

 +---+---+---++---+---+---++---+---+---+
 | 1 | 5 | 9 || 6 | 8 | 3 || 4 | 7 | 2 |
 +---+---+---++---+---+---++---+---+---+
 | 6 | 4 | 3 || 1 | 7 | 2 || 5 | 8 | 9 |
 +---+---+---++---+---+---++---+---+---+
 | 8 | 7 | 2 || 5 | 9 | 4 || 6 | 3 | 1 |
 +===+===+===++===+===+===++===+===+===+
 | 2 | 3 | 5 || 4 | 6 | 9 || 7 | 1 | 8 |
 +---+---+---++---+---+---++---+---+---+
 | 9 | 1 | 4 || 8 | 3 | 7 || 2 | 5 | 6 |
 +---+---+---++---+---+---++---+---+---+
 | 7 | 8 | 6 || 2 | 5 | 1 || 9 | 4 | 3 |
 +===+===+===++===+===+===++===+===+===+
 | 3 | 6 | 1 || 7 | 2 | 5 || 8 | 9 | 4 |
 +---+---+---++---+---+---++---+---+---+
 | 5 | 9 | 8 || 3 | 4 | 6 || 1 | 2 | 7 |
 +---+---+---++---+---+---++---+---+---+
 | 4 | 2 | 7 || 9 | 1 | 8 || 3 | 6 | 5 |
 +---+---+---++---+---+---++---+---+---+

しょぼいっす・・・。

  • 配列result[]を初期化するとき、もっと簡単にコピーする方法がありそう
  • check_row、check_column、check_blockのロジックはほとんど同じなので、ブロックを使うと1つにできそう
  • forでループを回すのがRubyっぽくないような気がする
  • proceed()でinitを引きずりまわさないで済む方法があるはず
  • バックトラックするときにわざわざresult[]にnilをセットし直しているのがスマートに見えない
  • そもそもアルゴリズムがしょぼい

勉強しながら書き直してみよう。
この日記を読んだ人へのお願い。他にもしょぼいところがあれば教えてください。でも、コードの書き方は決して教えないでください。

集合演算っぽくファイルの足し算と引き算をする

実は僕はソフトウェアエンジニアなのです。というわけで、(たしか)初の技術ネタ。
Unixファイルシステム上に、次のようなソート済みのfile1とfile2があるとします。

$ cat file1
a
b
d
e

$ cat file2
b
c
d
f

それぞれのファイルを集合、各行を要素と見なして、Unixコマンドのみで演算をしてみる。
file1とfile2を単純に足し算(結合)する場合はこう。

$ cat file1 file2
a
b
d
e
b
c
d
f

でも、これだと全然集合っぽくない。

和集合(file1∪file2)

file1とfile2の少なくとも一方に含まれる要素を重複なしでリストする。

$ cat file1 file2 | sort | uniq
a
b
c
d
e
f

こんな書き方もできる。

$ join -a1 -a2 file1 file2
a
b
c
d
e
f

差集合(file1―file2)

file1に含まれるけど、file2には含まれない要素をリスト。

$ diff file1 file2 | awk '/^</{print $2}'
a
e

分かりづらいので、diffの出力だけを見てみる。

$ diff file1 file2
1d0
< a
2a2
> c
4c4
< e
---
> f

'd'のセクションにリストされる要素は、file1にしか含まれないという意味なので、結果集合に含まれる。
'a'のセクションはfile2にのみ含まれるので、結果集合には含まれない。
'c'のセクションはfile1のほうの要素だけが結果集合に含まれる。
要は、行頭の文字が'<'の場合に、空白以降を出力すればよい。そのフィルターをawkでやっている。

積集合(file1∩file2)

file1とfile2の両方に含まれる要素をリスト。これは意外と楽チン。

$ join file1 file2
b
d

ザ・チョイス

「ザ・ゴール」シリーズは一通り読んでいるので、当然これも読む。

「ものごとはシンプル」
ええ、信じますとも。僕は素直な人間なので、たとえだまされたとしても、それを信じることによるデメリットがないと確信できるときは、どんな理論でも心の底から信じることができます。古くは禁煙セラピー―読むだけで絶対やめられる (ムックセレクト)がそうでした。最近だとフォトリーディングはしっかり信じてます。正直、ちょっと我流でカスタマイズした方法になってるけど。
でもまあ、実際のところ、本当にものごとは本来シンプルなんだろうと思うよ。何かが起きると、その理由を一生懸命探そうとする人たちがいるけど、探る価値のない理由しかないことや、本当に理由がないことってあると思う。
つまり、「なんでアナタは頼んだことやっておいてくれないの!?」とか怒られても困るんだよ。で、「なんで?と聞かれても、特に理由はなくて、単に忘れただけなんだよ」とか言うと、さらに怒られるのはなんでなんだろう?・・・と思ったけど、たぶんそれも大した理由はないので、気にしないことにしよう。

メディア・バイアス

日記は書かないけど、本はいちおう読んでるよ。

有機野菜=安全、というわけではないというのは初耳で驚いた。あと、マイナスイオンは科学ではないというのにも。環境ホルモンとか、元からなんのことなのかよく分かってなかったけど、既にその存在が否定されたものであることすら知らんかった。

でも、周囲の「有機野菜マンセー!」な人たちに教えてあげるのも面倒臭いな。「農薬が体に悪いと科学的に証明されているわけではないことは分かったけど、100%安全と証明されたわけでもないんでしょ?」とか言われるのは明らかだし。著者が言うとおり、それは詭弁なんだけど、それに気付いていない人に真っ正直に突っ込みを入れると、たいてい感情的な反感を買うことになるので、大人な俺は自分の子供にだけ教えてあげるくらいにとどめておこう。

ってか、俺にこんな気を遣わせてくれるな、マスコミよ。

やっぱりOracleか

やっぱり当った。って、誰でも当るか。
http://d.hatena.ne.jp/yebihara/20090320/1237567875

でも、Sunを買うならOracleだと思ってたんだけどな。Oracleが持っていないものはあとハードウェア(既にストレージはいちおうあるが)とゲームくらいだし。

でもIBMの話がぽしゃった時点で、残りのSun株は全て処分しちゃってたんだよね。俺って弱い。

それにしてもOracleがHPと協業して作ったExadataはどうなるのかな? Sunテクノロジーベースで作り直したら面白いなぁ。野次馬根性的に面白いだけだけど。

あとMySQLPostgreSQLの行く末も気になる。MySQLは旧経営陣がMBOするしかないんじゃないの? まちがってもOracle DB、TimesTen、BerkleyDB、InnoDBとかのラインナップに並んで欲しくないなぁ。
PostgreSQLのほうは、SunがMySQLを買収する前から、コアデベロッパーを雇ってたりしてたんだけど、その人たちはEnterpriseDBに行けばいいか。

IBMがSunを買収だって?

今さらながらのコメント。でも報道直後にコメント書いて、変にページビュー増えても困るし。
以前に久しぶりにUS株を買ったという話しを書いた。
http://d.hatena.ne.jp/yebihara/20081206/1228535712
そう、このとき買っておいたSun株が、今回のIBMが買収するという報道でようやくプラスに転じました。
買収金額が報道された通りなら株価は$10くらいまで上昇するはずだが、直後のマーケットは$8台。その差額は買収が不調に終わるかもしれないという不確定さを表しているということだろう。
$10には足りないが、買収失敗で元の株価になる可能性もあるので、とりあえず半分売ってあとは様子見。
それにしてもSunがなくなるかもしれないというのは、僕の中ではDEC以来の衝撃かな(Compaqのときは驚きはしたがショックではなかった)。ソフトウェア企業は最近のOracleの買収攻勢のおかげで、かなり耐性ができていたんだけど。ちょっと寂しいね。
でも、Sunを買うならOracleだと思ってたんだけどな。Oracleが持っていないものはあとハードウェア(既にストレージはいちおうあるが)とゲームくらいだし。