追記

ヽ(´・肉・`)ノログ

2005|05|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|11|12|
2010|01|02|03|04|05|06|07|

2010-07-25 [長年日記]

[]

2010-07-22 [長年日記]

_ [java] Collection / Generics

今日はコレクションをやりました.良く使う割にはあんまり知らないことがあったなぁ

20100722研修

collection

java collection framework
  • List
    • ArrayList
    • LinkedList
  • Set (null なし)
    • HashSet
  • Map (null あり)
    • HashMap
  • SortedMap 順序ありMap
    • TreeMap
  • SortedSet 順序ありSet
    • TreeSet
Comparator と Comparable

Comparable は interface で int compareTo(T obj) というメソッドを持っている.1,2,3とかa,b,cとか自然な順序を比較することができるというinterface.compareToで自分自身と比べる.Comparator も interface だけど,int compare(T obj1, T obj2) という風に,2つのオブジェクトを比較するためのインターフェース.Arrays.sort(someList, new SomeComparator()); という風に使う.

Comparable
このオブジェクト自身を比較できますよという印
Comparator
比較するためのオブジェクトですよという印
equals / hashCode

Object にある public method.変える時は適切にオーバーライドする.

equals

意味として等しいか?を示す.

たとえば,50円が2つ入っているリストを持つオブジェクトと,100円が1つ入っているリストを持つオブジェクトは等しいか?

  • 金額という観点から => 50*2=100 だから等しい
  • 種類という観点から => 50 と 100 だから異なる

そのオブジェクトをどういう風に使いたいかによって,「等しさ」は異なる.使う人間が定義してやらないといけない.

オマケ 同値(等しさ)の定理は以下の3つ

  • X=X
  • X=Y なら Y=X
  • X=Y Y=Z なら X=Z
hashCode
public int hashCode()

つまり,無限に存在するオブジェクトを,int数だけの有限空間に無理矢理突っこむという関数.異なるオブジェクトが同じhashCodeを返してもいい.やらないし,やらないほうがいいけど

public int hashCode(){
    return 0;
}

とか定数も禁止されてはいない.↑でやったMapやSetに値を入れる時のキーなどに使う.


generics

1.5から導入された.1.4以前だと

List list = new ArrayList();
list.add("A");
list.add(new Integer(100));

String s = (String) list.get(0);

みたいに書かないといけない.

  • 取るときのキャストがめんどくさい
  • そもそも一つのリストにいろんなオブジェクト入れる事あんまりないよね

という理由から,「あるリストに決められたオブジェクトしか入れられない」と決めて,取るときのキャストを不要にした書き方を用意した.それがジェネリクス.こんなの

List<String> list = new ArrayList<String>();
リストに決められたオブジェクトしか入れられないのは,いつチェックしてる?

コンパイルの時.

コンパイルした後のバイトコードにはジェネリクスの情報は入っていない(イレイジャー erasure).後方互換性(1.4でコンパイルできるものが1.5でコンパイルしてもちゃんと動く)のためにそうなっている.

extends / super
List<Number> list = new ArrayList<Number>();
list.add(new Integer(100)); // できない

はコンパイルエラーになる.なぜか?「IntegerはNumberではない」から.ジェネリクスでは普通にやるとオブジェクトの継承関係を見てはくれない.

不便すぎるので,ワイルドカードを用意した

List<?> list = new ArrayList<Object>();

で何でも入れられるリストになる.

でもそれだと1.4と同じ状態になってしまうので,条件つきのワイルドカードを用意した

List<? extends Number> list = new ArrayList<Number>();
list.add(new Integer(100)); // できる!!

これで「Number型を持つもの」をリストに入れられる.同様に <? super T> でTの親ならを何でも入れられるリストを作れる.でも〜の親ってあんまり宣言する機会がない.

[]

2010-07-20 [長年日記]

_ [java] オートボクシング/enum まとめ

今,僕の行っている会社ではJavaの研修をやってくれるのです.素晴しいですね.せっかくなので覚えた部分をまとめてみました.今日はオートボクシングと列挙型です.

20100720研修

ボクシング・アンボクシング

どんなの?

オブジェクト型とプリミティブ型を相互に変換する

オブジェクトとプリミティブの違いは?
  • 本質
    • メモリの使い方
  • 特徴
    • プリミティブだとレシーバーを取れない ex) 1.plus(2)とかできない
    • プリミティブだとnullを入れられない(初期値がある)
    • プリミティブだと型を使ってポリモーフィズムを表現できない
あれ,プリミティブに良い所あるの?

軽くて速いよ!

いつやるの?

コンパイル時にやる

ボクシング
  • プリミティブ->オブジェクト自動変換
  • Integer.valueOf(prim) を使うと思いねぇ
アンボクシング
  • オブジェクト->プリミティブ自動変換
  • obj.intValue()を使うと思いねぇ.つまりobjがnullだとNullPointerExceptionになる
コンパイル時にnullチェックしてよ

できない.例えば秒数末尾が偶数ならnull,奇数ならオブジェクトを生成とか,コンパイル時に調べられない.

void method(int num)l{} と void method(Integer num) は同じクラス内に書ける?

書ける.オートボクシング導入(1.5)より前ではこれは普通のことだった.method(int型); だと前者,method(Integer型); だと後者が呼ばれる.

列挙型(enum)

どんなの?
  • 特殊なクラス.
  • 同じ種類の定数を集めて書いておく時なんかに使う. enum Direction{ UP, DOWN, LEFT, RIGHT}; のような感じ.
  • UP, DOWN, LEFT, RIGHT の値が一意になることは保証されている.
[]

2010-07-14 [長年日記]

_ [ruby] twitterのlistに登録されているmemberをfollowするrubyスクリプト

twitterで,あるユーザーが作成したリストに含まれているメンバーを一括followするrubyスクリプトです.ruby1.9で動作確認しました.

# -*- coding: utf-8 -*-
require 'logger'
require 'rubytter'

LOG = Logger.new('follow_user_on_the_list.log')
USER = 'niku_name' # your twitter account
PASS = ''   # your twitter password

# ex) follow list "http://twitter.com/hdhsakym/robocup"
TARGET_USER = 'hdhsakym'
TARGET_LIST = 'robocup'

# oauth = Rubytter::OAuth.new(CONSUMER_KEY, CONSUMER_SECRET)
# access_token = OAuth::AccessToken.new(oauth.create_consumer, ACCESS_TOKEN, ACCESS_SECRET)
# @client = OAuthRubytter.new(access_token) # 2010/05/16現在 OAuth だと list 操作が 404 Not Found になる
@client = Rubytter.new(USER, PASS)

def all_users
  ary = []
  next_cursor = -1
  while next_cursor != 0
    begin
      res = @client.list_members(TARGET_USER, TARGET_LIST, {cursor:next_cursor})
    rescue => ex
      LOG.warn ex
      sleep 10
      retry
    end
    ary.concat res.users
    next_cursor = res.next_cursor
    LOG.info "next_cursor is #{next_cursor}"
    sleep 60
  end
  ary
end

all_users.each do |user|
  LOG.info "#{user[:screen_name]}処理中..."
  begin
    @client.follow user[:screen_name]
    sleep 60
  rescue => ex
    LOG.warn ex
    sleep 10
    retry
  end
end
[]

2010-06-24 [長年日記]

_ [ruby] 整数値から紙幣の枚数をハッシュで返す

6152円はN円札がM枚…とかいうアレです."6152.bill"で紙幣の単位と枚数のハッシュを返すようにしてみました.

class Integer
  def bill
    raise if self < 0
    unit = [10000, 5000, 2000, 1000, 500, 100, 50, 10, 5, 1]
    unit.inject({}) do |result,item|
      remain = self - result.inject(0){ |r, i| r += i.inject(:*) }
      result[item] = remain/item
      result
    end
  end
end

0.bill                        # => {10000=>0, 5000=>0, 2000=>0, 1000=>0, 500=>0, 100=>0, 50=>0, 10=>0, 5=>0, 1=>0}
3.bill                        # => {10000=>0, 5000=>0, 2000=>0, 1000=>0, 500=>0, 100=>0, 50=>0, 10=>0, 5=>0, 1=>3}
6152.bill                     # => {10000=>0, 5000=>1, 2000=>0, 1000=>1, 500=>0, 100=>1, 50=>1, 10=>0, 5=>0, 1=>2}
18947.bill                    # => {10000=>1, 5000=>1, 2000=>1, 1000=>1, 500=>1, 100=>4, 50=>0, 10=>4, 5=>1, 1=>2}
begin
  -1.bill                       # => 
rescue => ex
  ex                            # => RuntimeError
end
[]

2010-06-23 [長年日記]

_ [ruby][gae][product]twitter for iPhoneから自分のtumblrに投稿する方法

twitter for iPhoneでは投稿に画像を添付することができ,設定で投稿先を選べます.通常はtwitpicとかyfrogになるのですが,google apps engineを利用して,自分のtumblrへ投稿することができました.

サーバー側

まずgithubからソースを取得します

git clone git@github.com:niku/twitter_for_iphone_gateway.git

取得したディレクトリのconfig.yamlに自分のtwitterアカウント情報とtumblrアカウント情報を記述します.

google application engineのアプリケーション名を決めて,config.ruに記述します.今twifigになっていますが,たぶん同じ名前は使えないんじゃないかな.記述したら,その名前でgaeにアプリケーションを作成しておきます.

ファイルをgaeにアップロードします.

appcfg.rb . update

iPhone側

twitter for iPhoneを起動したら アカウント選択画面 が出るので,印でくくった部分をタップ.以下も同じです.

設定画面

連携サービス画面

画像サービス画面

カスタム画面 ここは先ほどgaeへアップロードしたアプリの名前に置き換えてください.

https://"アプリケーション名".appspot.com/image

です.

どうなる?

twitter for iPhone から画像つきで投稿すると,twitterは http://twitter.com/niku_name/status/16783623668 のようになり,tumblrは http://tumblr.niku.name/post/725826838 のようになります.

参考にしたサイト

http://developer.atebits.com/tweetie-iphone/custom-image/ にtwitter for iPhoneの画像投稿時に送る情報が載っていました.

http://www.tumblr.com/docs/en/api にtumblrのAPI情報が載っていました

[]

2010-06-05 [長年日記]

_ [ruby] twitterでしばらくpostしていない人をfollowから外すと同時にリストに加えるスクリプト

簡単でした.そうrubytterならね.

# -*- coding: utf-8 -*-
require 'logger'
require 'time'
require 'uri'
require 'net/http'
require 'rubytter'

LOG = Logger.new(STDOUT)
USER = '' # your twitter account
PASS = '' # your twitter password
LIST_NAME = '' # create twitter list name ex) last-post-was-quarter-year-ago
PAST_TIME = Time.now - 60 * 60 * 24 * 90 # quarter year

#oauth = Rubytter::OAuth.new(CONSUMER_KEY, CONSUMER_SECRET)
#access_token = OAuth::AccessToken.new(oauth.create_consumer, ACCESS_TOKEN, ACCESS_SECRET)
#@client = OAuthRubytter.new(access_token) # 2010/05/16現在 OAuth だと list 操作が 404 Not Found になる
@client = Rubytter.new(USER, PASS)

begin
  @client.list(USER, LIST_NAME)
rescue Rubytter::APIError
  @client.create_list(LIST_NAME) # リストが無ければ作成する
end

def all_friends
  ary = []
  next_cursor = -1
  while next_cursor != 0
    begin
      res = @client.friends(USER, {cursor:next_cursor})
    rescue => ex
      LOG.warn ex
      sleep 10
      retry
    end
    ary.concat res.users
    next_cursor = res.next_cursor
    LOG.info "next_cursor is #{next_cursor}"
    sleep 60
  end
  ary
end


all_friends.select { |friend|
  if friend.statuses_count == 0
    true
  else
    Time.parse(friend.status.created_at) < PAST_TIME
  end
}.tap{ |e| LOG.info "対象は#{e.size}人くらいいます" }.each{ |friend|
  name = friend.screen_name
  LOG.info "#{name}処理中..."
  begin
    @client.add_member_to_list(LIST_NAME, name) if @client.user(name).statuses_count != 0 # 0ポストの人はリスト登録に失敗する
    @client.leave(name)
    sleep 60
  rescue => ex
    LOG.warn ex
    sleep 10
    retry
  end
}

_ [ruby]rubytterでfollowしている人全てを取得する方法

通常のTwitterAPIではcursorというのを指定して値を全取得します.rubytterでcursorを使うにはfriendsの2番目の引数にハッシュで指定してやればOKでした.

# -*- coding: utf-8 -*-
require 'rubytter'
require 'oauth'

USER = ''
CONSUMER_KEY = ''
CONSUMER_SECRET = ''
ACCESS_TOKEN = ''
ACCESS_TOKEN_SECRET = ''

oauth = Rubytter::OAuth.new(CONSUMER_KEY, CONSUMER_SECRET)
access_token = OAuth::AccessToken.new(oauth.create_consumer, ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
@client = OAuthRubytter.new(access_token)
def all_friends
  ary = []
  next_cursor = -1
  while next_cursor != 0
    res = @client.friends(USER, {cursor:next_cursor})
    ary.concat res.users
    next_cursor = res.next_cursor
    p next_cursor
  end
  ary
end

p all_friends
[]

2010-06-03 [長年日記]

_ [ruby] twitterのbioに特定のキーワードを書いている人を集めてlistにした(twpro対応)

twitterの自己紹介欄に「consadole」や「コンサドーレ」と書いてある人をリストに加えるスクリプトです. http://niku.name/20100516.html#p01 の改良版です.http://twpro.jp/ で検索した人も加えるようにしました.twproはajaxで値を返してくるので解析がちょっと面倒でした.API用意してくれないかな.コードは汚いけど使い捨てだからいいかなと思っています.

# -*- coding: utf-8 -*-
require 'uri'
require 'net/http'
require 'nokogiri'
require 'oauth'
require 'rubytter'

USER = 'niku_name'
PASS = ''
#CONSUMER_KEY = ''
#CONSUMER_SECRET = ''
#ACCESS_TOKEN = ''
#ACCESS_SECRET = ''
#PIN = ''

LIMIT = 500 # 500 は list 登録人数の上限値
SEARCH_WORDS = ['コンサドーレ', 'consadole']
LIST_NAME = 'consadole'

def get_members_from_lefthandle search_word
  (0..(1/0.0)).inject([]) do |base, num|
    uri = URI.parse("http://tps.lefthandle.net/search/#{num}/?s=#{URI.encode search_word}&sort=follower")
    doc = Nokogiri::HTML(Net::HTTP::get(uri))
    result = doc.search('div.tweetuser').map{|e| e['id']}
    if result.empty?
      break base
    else
      base.concat result
    end
  end
end
def get_members_from_twpro search_word
  (1..(1/0.0)).inject([]) do |base, num|
    result = Net::HTTP::post_form(URI.parse("http://twpro.jp/search/search/#{num}"), word:search_word).body.scan /<span class='name'><a href='http:\/\/twitter\.com\/(\w+)'>/
    if result.empty?
      break base
    else
      base.concat result
    end
  end
end
members = SEARCH_WORDS.map{ |search_word|
  lefthandle = get_members_from_lefthandle(search_word)
  twpro = get_members_from_twpro(search_word)
  lefthandle.concat(twpro)
}.flatten.uniq

oauth = Rubytter::OAuth.new(CONSUMER_KEY, CONSUMER_SECRET)
access_token = OAuth::AccessToken.new(oauth.create_consumer, ACCESS_TOKEN, ACCESS_SECRET)
#client = OAuthRubytter.new(access_token) # 2010/05/16現在 OAuth だと list 操作が 404 Not Found になる
client = Rubytter.new(USER, PASS)

begin
  client.list(USER, LIST_NAME)
rescue Rubytter::APIError
  client.create_list(LIST_NAME) # リストが無ければ作成する
end

# リストに登録
members.each do |member|
  p member
  begin
    client.add_member_to_list(LIST_NAME, member)
  rescue => ex
    p ex
    next if client.user(member).statuses_count == 0 # 0ポストの人は登録に失敗する
    sleep 10
    retry
  end
end
[]

2010-05-25 [長年日記]

_ bookscanにscanを依頼した本の一部がページ抜けしていた(かもしれない)

@bookscan_jpにスキャンを依頼したのですが,そのうち「Rubyベストプラクティス」のスキャン結果にページ抜けがあることに気づきました.

応援していますし,安い値段でやっている以上仕方ないのかなとは思いますが,ほぼ新刊の状態の本でこれだけ抜けられると,今後お願いするのには躊躇してしまいますね…

題にかもしれないと記述したのは,本の落丁の可能性は否定できないためです.あるいは元々こういうページ構成だったとか.この本をお持ちの方,まえがきの辺りの正しいページ構成はどのようになっているでしょうか?

連続したスクリーンショットは以下のような感じです

5,7ページ 5ページの後に7ページがあります.紙づまりした後のオペレーションを誤ったのでしょうか.6と8ページはどこに…

9,10ページ ここは問題ありません

11,12ページ ここも問題ありません

13,14ページ ここまでは問題ありませんでした

17,18ページ 15ページと16ページが抜けました

19,本文1ページ ここは問題ありません

[]

2010-05-24 [長年日記]

_ 暑かったり寒かったり

今日の朝の通勤電車です.1回目の電車は暖房が入っていて,2回目の電車は冷房が入っていました.なんだか不思議ですね.あれどうやって決めてるんだろう…運転手さんの裁量なのかな.

[]

追記