Pythonでswitch

twitterで"なんでPythonにはswitchがないの?"とぼやいたところ、ハカーの皆さんがPythonでswitchの実装を教えてくれた。それが勉強になったので僭越ながらご紹介。

Ian Lewisさん、akisutesamaさんより
breakし忘れてひどいバグを作る子がいるから
ifelifで。

これはごもっとも。っていうかこれしか知らないwww

MiCHiLUさんより
dictを使う{1:lambda x:x, 2:lambda x:x*x, 3:lambda x:x*x*x}.get(4, lambda x:'Infinity')(100)

lambdaを使ってこんなことまでできるとは・・・。hirokinkoさんはjavaでHashMapを使って同じような実装をされているそうです。

id:moriyoshiさんより
switchを作っていただきました。
def switch(name, bases, dict):
  dict.get(bases[0], lambda:0)()
  return type(name, tuple(), dict)

class _('a'):
  __metaclass__ = switch
  def a():
    print 'a'

  def b():
    print 'b'

こちらに保存させてもらいました。これは使いたいコードすぎです。

勉強になります!皆様ありがとうございます^^

TopCoder - SRM 425 DIV 2: 500

SRM 425 DIV 1: 250と同一問題。これ難しかった。とりあえずやっつけでやってみた。コードはこちら。312点…。問題は、東西南北自由に動き回るロボットが指定回数動いたときに、同じ地点に戻ってこない確率を求めるというもの。

public class CrazyBot {
  double we, ww, ws, wn;
  double total = 0.0;
  public double getProbability(
    int n,
    int east,
    int west,
    int south,
    int north) {
    int sum = east + west + south + north;
    we = east * 1.0 / sum;
    ww = west * 1.0 / sum;
    ws = south * 1.0 / sum;
    wn = north * 1.0 / sum;
    boolean flag[][] = new boolean[n*2+1][n*2+1];
    move(flag, n, n, 1.0, n);
    return total;
  }
  public void move(
    boolean flag[][],
    int x, int y, double p, int n) {
    if (flag[x][y]) {
      return;
    }
    if (n < 0) {
      return;
    }
    if (n == 0) {
      total += p;
      return;
    }
    flag[x][y] = true;
    if (we > 0.0) {
      move(flag, x+1, y, p * we, n-1);
    }
    if (ww > 0.0) {
      move(flag, x-1, y, p * ww, n-1);
    }
    if (ws > 0.0) {
      move(flag, x, y-1, p * ws, n-1);
    }
    if (wn > 0.0) {
      move(flag, x, y+1, p * wn, n-1);
    }
    flag[x][y] = false;
  }
}

TopCoder - SRM 425 DIV 2: 250

今回は、数値配列の中で、その数値配列内の数値を含まない最小公約数を求める問題。コードはいつものとこ。皆さんのコードを見てたら、たいていの方が、ただ単にmax * minでだしてた・・・。それで良いのかwww?

import java.util.Arrays;

public class InverseFactoring {
  public int getTheNumber(int[] factors) {
    Arrays.sort(factors);
    int lcm = factors[0];
    for (int i=1; i<factors.length; i++) {
      lcm = getLcm(lcm, factors[i]);
    }
    if (lcm == factors[factors.length - 1]) {
      return lcm * 2;
    } else {
      return lcm;
    }
  }
  int getGcd (int x, int y) {
    int z=x%y;
    if(z==0) {
      return y;
    } else {
      return getGcd(y, z);
    }
  }
  int getLcm (int x, int y) {
    return x/getGcd(x,y)*y;
  }
}

BigTableはPUSH型で

BigTableで悩むで書いたけど、Twitterでid:Voluntasさんからアドバイスを頂きました。

ということでPULL型で作っていたのをフルスクラッチしたいと思います。id:Voluntasさんありがとうございます。最初からちゃんとBigTableのこと調べてから設計すべきwww

TopCoder - SRM 144 DIV 2: 500

うんむ・・・。難題にぶち当たって先に進まないから、息抜き(?)にTopCoderを解いた。なぜかストレス発散になるwww今回の問題は与えられた数値が何個の数値で割り切れるのかを求めるもの。割り切れない場合は'-1'を返す。

public class ProductOfDigits {
  public int smallestNumber(int N) {
    int i;
    for (i=1; true; i++) {
      int j = getint(N);
      if (j==-1) {
        return -1;
      }
      N = N / j;
      System.out.println("N:"+N+" J:"+j);
      if (N==1) {
        break;
      }
    }
    return i;
  }
  int getint (int N) {
    for (int i=9; i>1; i--) {
      if (N%i==0) {
        return i;
      }
    }
    return -1;
  }
}

BigTableで悩む

GAEでTwitterライクなアプリを作ってるんだけど、BigTableのリレーションで悩んでる。モデルは以下のようにした。ちなみにZipped Django 1.0 on GAE with Helperをベースにしている。


# models.py
class User(BaseModel):
  user = db.UserProperty(required=True)
  follow = db.ListProperty(db.Key) # User model
  send = db.ListProperty(db.Key) # Item model 送信したItem
  receive = db.ListProperty(db.Key) #Item model 受信したItem
class class Item(BaseModel):
  text = db.StringProperty(required=True) # 送信したtxt
  published = db.DateTimeProperty(required=True, auto_now_add=True) # 送信したtxt

上記モデルから、"自分がFollowしたUserの全てのItem+自分が受信したItem"、"自分が受信したItem"、"自分が送信したItem"を(Twitterみたいにw)取得したい。そこで以下のように抽出する。


# views.py
def received (request): # 自分が受信したItem
  user = User.all().filter('user =',users.get_current_user())
  items = Item.get(profile.receive)

def sent (request): # 自分が送信したItem
  user = User.all().filter('user =',users.get_current_user())
  items = Item.get(profile.send)

def home (request): # 自分がFollowしたUserの全てのItem+自分が受信したItem
  user = User.all().filter('user =',users.get_current_user())
  itemkeys = profile.receive
  for (follow in profile.follow):
    user = User.get(follow)
    itemkeys.append(user.send)
  items = Item.get(itemkeys)

というかんじでItemを受信している。ただし、itemsblishedの降順で並べ変えたいのに、これではgoogle.appengine.ext.db.Queryが使えないため、itemsに.order('-blished')ができず、itemsappend()した順番に取れてきてしまう。うむ・・・どうすれば非リレーショナルなDBでTwitterもどきができるのだろうか・・。

TopCoder - SRM 424 DIV 2: 250

今回も英語に苦しみました・・・。英語勉強しないとですね。今回の問題は英大文字の文字列の中から、'A'と'Z'を抜き出し、その文字列の中で順番を反転するというもの。コードはソースコードビューアに保存しました。いつも思うけどおれのコードは長い。

public class MagicSpell {
  public String fixTheSpell(String spell) {
    char[] c = spell.toCharArray();
    int r = c.length;
    for (int i=0;i<c.length;i++) {
      if (c[i]=='A'||c[i]=='Z'){
        System.out.println("i:"+c[i]);
        for (int j=r;j>0;j--) {
          if (c[j-1]=='A'||c[j-1]=='Z'){
            System.out.println("j:"+c[j-1]);
            char temp = c[j-1];
            c[j-1]=c[i];
            c[i]=temp;
            r=j-1;
            break;
          }
        }
      }
      if (i>=r-1) {
        break;
      }
    }
    return new String(c);
  }
}

Zipped Django on GAE with Helper

Zipimortを使ってApp EngineでDjango 1.0を利用するでGAEにZipアーカイブされたDjango 1.0を使う手順を翻訳したけど、ついでに既存のDjangoアプリをそのまんま乗っけちゃうためにGoogle App Engine Helper for Djangoを使いたい。ということで、テンプレートを作りました。Githubに置いときます。適当にforkして使っちゃって下さい。ここはHelper、Djangoがバージョンアップするつど更新していきたいと思います。今回使ったバージョンは以下のとおりです。

このテストサイトで動かしています。Django 1.0を使いたい方はdjangoproject.jpの皆様がドキュメントを翻訳して下さってますので、ここをご参考にしてください。