スリープ探索
スリープ探索アルゴリズム[Chishow PRESENTS BLOG]
最初は,スリプーソートのインパクトと比べて弱いなーと思ったんだけど,コスト比較とコスト計算が分離できるのは悪くないんじゃなかろうかと思えてきた.
多分,A*とかで書いたほうが早いだろうけども.
スレッド未使用版SleepSortクラス
class SoftSleepSort def initialize @threads = [] end def push( priority, &block) @threads << {:prio => priority, :func => block} @threads = @threads.sort_by{|h| h[:prio] } end def pop return if empty? h = @threads.shift h[:func].call end def wait_all while(not empty?) do pop end end def empty? @threads.empty? end end =begin # 単純なソート ar = [] 1.upto(10){|i| ar << (rand()*100).to_i } sss = SoftSleepSort.new ar.each{|x| sss.push(x) { p x} } sss.wait_all =end
スリープ探索
# 経路は http://yukirin.dontexist.org/archives/741 から借用 nodes = { "s" => {"a" => 5, "b" => 4, "c" => 2}, "a" => {"s" => 5, "g" => 6, "b" => 2}, "b" => {"s" => 4, "a" => 2, "c" => 3, "d" => 2}, "c" => {"s" => 2, "b" => 3, "d" => 6}, "d" => {"c" => 6, "b" => 2, "g" => 4}, "g" => {"a" => 6, "d" => 4}, } start_node = "s" goal_node = "g" map_memo = {} sss2 = SoftSleepSort.new calc_cost = Proc.new{|total_cost, current_node, route| result = false if (current_node==goal_node) puts "#{total_cost}: #{route.join(' -> ')}" result = true else nodes[current_node].each{|next_node, cost| c = total_cost + cost c2 = map_memo[next_node] # 初めての場所、または既出より短い経路なら探索を行う if (c2==nil or c2>c) map_memo[next_node] = c sss2.push(c) { calc_cost.call( c, next_node, route+[next_node] ) } end } end result } calc_cost.call( 0, start_node, [start_node] ) # 探索が終了するか、ゴールに到達する経路が出現するまで取り出す。 while(not sss2.empty? and not sss2.pop) do ; end
最初は,無名のプロシージャにするためにYコンビネータを使って書いたけど,別にそんなことする必要なかった.
group
フラットな配列を指定の数ずつまとめる.
たまにあったら便利なのにと思いつつ,必要になるたびに手書きしてる.
すでに標準であったりして.
class Array def group(n=2) return [] if empty? if false and (size % n != 0) puts "error in group #{size}%#{n}=#{size%n}" return nil end ret = [] 0.upto(size/n-1) {|x| ret << self[x*n,n]} ret end end
p [1,2].group(2) # => [[1, 2]] p [1,2,3,4,5,6].group # => [[1, 2], [3, 4], [5, 6]] p (1..6).to_a.group(3) # => [[1, 2, 3], [4, 5, 6]] p (1..5).to_a.group(3) # => [[1, 2, 3]]
エスケープ
xmlつうかrssで取得した中身に入ってる&nbsp;をどうやったら戻せるのか?そもそも&gt;を'>'に変換することをなんていうのか分らないので検索さえできない.
グーグル先生を問い詰めて,実体参照とかエスケープとかいうキーワードを聞き出すものの,常識的過ぎて誰も書かないのか,それとも&gt;を戻したりしないのか,探し方が悪いのかなかなか見つからない.
ようやく2007-02-13 - nazonoDiaryにたどり着く.これですよこれ.
utf8は使わないのでsjis用に改造してみた:
require "cgi" require "kconv" class CGI # HTMLエンティティーの定義 HtmlEntityList = Hash[ *%w(nbsp 160 iexcl 161 cent 162 pound 163 curren 164 (略) rsaquo 8250 euro 8364) ] HtmlEntity = HtmlEntityList.inject({}){|r,v| a = [v[1].to_i].pack("U") case $KCODE when 'SJIS'; a = a.kconv( Kconv::SJIS, Kconv::UTF8) end r[v[0]] = a if a!="" or v[0]=='nbsp' r } # CGI.unescapeHtml の修正版 def self.unescapeHTML( string ) string.gsub(/&([^&;]{2,8});/n) {|ma| HtmlEntity[$1] or ma } end end def unescape str; CGI.unescapeHTML str; end
リストにないエスケープ文字列の扱いがオリジナルと違ってます.
最初にブラウザ上で書いてコミットしたらメンテ中ってなって文章が消えた.対した量じゃないけど.ちゃんとエディタに書いてからコピペすればよかった.
Top Down Operator Precedence
beautiful codeの 9章 下向き演算子順位解析を写経してみたら,いろいろ端折ったのに500行以上になった.思ったより長い.
最初の所はこんな感じ:
$original_symbol = Prototype.new $original_symbol.error = lambda() {|x| raise x } $original_symbol.nud = lambda() { self.error "undefined." } $original_symbol.led = lambda() { self.error "missing operator." } $symbol_table = {} def symbol( id, bp=0) s = $symbol_table[id] if s s.lbp = bp if bp >= s.lbp else s = $original_symbol.clone s.tok = s.value = id s.lbp = bp $symbol_table[id] = s end s end %w": ; , ) ] } else (end) (name)".each{|x| symbol x } symbol("(literal)").nud = lambda() { self } symbol("this").nud = lambda() { $scope.reserve(self) self.arity = "this" self }
Prototypeはhttp://d.hatena.ne.jp/iken0/20080625/p1で定義したやつ.
関数とブロック付きの関数呼び出しの両方で文法を定義するのが微妙な感じがする.