PubMedのシンプソン数

おとなり日記からのぞいてみた記事*1に触発されて作ってみました。
PubMedもシンプソン数も何に使うのかよくわかってないです。><)

追記

map_countの定義のところで無駄がありました><

  • lambda/procを関数内関数のように使うと遅くなる
  • それ以前に、map_countのしている処理はひとつだけ
    • mapperが要らない。
#!/usr/bin/env ruby
require 'rexml/document'
require 'open-uri'

def count(gene)
  url = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term="+gene
  
  source = open(url).read
  doc = REXML::Document.new source
  return doc.elements['/eSearchResult/Count'].text.to_i
end

#p map_count([[1,2],3]) => [[count(1), count(2)],count(3)]
#たくさん調べるときに
def map_count arr
  arr.map { |e| (e.respond_to? :flatten)? map_count(e) : count(e)}
end
##=============前に作った時の=========
##def map_count arr  
##  #Arrayオブジェクトならflattenを持ってるかな〜ってことで
##  mapper = proc do |a| 
##    a.map { |e| (e.respond_to? :flatten)? mapper.call(e) : count(e)}
##  end
##  
##  mapper[arr]
##end
##====================================

#シンプソン数を調べる前に負の数をチェック
def ok? arr
  arr.flatten.each {|e| return false if e < 0}
  true
end

#シンプソン数の計算
def simpson args  #[[count(x), count(y)], count(xny)]という感じの配列が引数になります。
exit(-1) unless ok? args
  args[1] / args[0].min.to_f
end

#配列の要素からそれぞれのシンプソン数を求める
def calc_simpson_from_array arr
  combinations = (all_comb(arr))
  num_array = map_count(combinations)

 labels = combinations.map{|e| e[1].to_s}
  labels.zip(num_array.map{|e| simpson(e)})
end

def all_comb elems 
  dp = proc {|a,b| a.map {|ae| b.map {|be| ae+"+"+be}}}
  result = []
  
  until elems.empty?
    tmp = elems.shift
    result << elems.map {|e| dp.call(tmp,e)}
  end
  result.flatten!.map {|e| [e.split("+"),e]}
end

def main *args
  exit(-1) if args.size < 2
  calc_simpson_from_array(args)
end

main ARGV


if $0 == __FILE__
seed = ["CDK2", "CDK6", "CDK3", "CDK5"]
(calc_simpson_from_array(seed)).each {|e| p e}

#==結果==
#["CDK2+CDK6", 0.432032301480485]
#["CDK2+CDK3", 0.680851063829787]
#["CDK2+CDK5", 0.127956989247312]
#["CDK6+CDK3", 0.191489361702128]
#["CDK6+CDK5", 0.0390309555854643]
#["CDK3+CDK5", 0.297872340425532]
end