public
Last active

  • Download Gist
README
1 2 3 4 5 6 7
This is my solution to RPCFN #13: Economics 101
http://rubylearning.com/blog/2010/08/31/rpcfn-economics-101-13
 
I used 3 ways to solve it:
- using Hpricot and Nokogiri
- using RegExp
- parsing the questions (and even write them in pure Ruby (no String))
hpricot18.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
# 1 What is the population of the country with the most people? Yes, we know it’s China, but just how many people lived there in 1996?
# 2 What are the five countries with the highest inflation rates, and what were those rates in 1996?
# 3 What are the six continents in the file and which countries belong to which continent? Can you also produce them in alphabetical order?
 
# Idea: parse these sentences to make the search :p
 
require 'rubygems'
require 'hpricot'
 
doc = open('cia-1996.xml') { |f| Hpricot(f) }
 
# Countries without population (25/260)
# p countries.select { |country| country['population'].nil? }.map { |country| country['name'] }
 
# 1 What is the population of the country with the most people? Yes, we know it’s China, but just how many people lived there in 1996?
# China
# 1 210 004 956
countries = doc / :country # or doc.xpath('/cia/country')
china = countries.max_by { |country| country[:population].to_i }
puts china[:name]
puts china[:population].reverse.chars.each_slice(3).map(&:join).join(' ').reverse
 
puts
# 2 What are the five countries with the highest inflation rates, and what were those rates in 1996?
# {"Belarus"=>244.0, "Turkey"=>94.0, "Azerbaijan"=>85.0, "Malawi"=>83.3, "Yemen"=>71.3}
 
cc = countries.dup
p 5.times.inject({}) { |h,_|
c = cc.delete cc.max_by { |c| c[:inflation].to_f }
h[c[:name]] = c[:inflation].to_f
h
}
 
p countries.sort_by { |country| - country[:inflation].to_f }[0...5].inject({}) { |h,c| h[c[:name]] = c[:inflation].to_f and h }
 
puts
# 3 What are the six continents in the file and which countries belong to which continent? Can you also produce them in alphabetical order?
# ["Europe", "Asia", "North America", "Australia/Oceania", "South America", "Africa"]
 
p continents = (doc / :continent).map { |continent| continent[:name] }
puts
countries_by_continent = countries.inject(Hash.new { |h,k| h[k] = [] }) { |h,country|
h[country[:continent]] << country[:name]
h
}
p Hash[countries_by_continent.sort_by { |continent, countries| countries.sort and continent }]
nokogiri.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
# 1 What is the population of the country with the most people? Yes, we know it’s China, but just how many people lived there in 1996?
# 2 What are the five countries with the highest inflation rates, and what were those rates in 1996?
# 3 What are the six continents in the file and which countries belong to which continent? Can you also produce them in alphabetical order?
 
# Idea: parse these sentences to make the search :p
 
require 'nokogiri'
doc = Nokogiri open 'cia-1996.xml'
 
# Countries without population (25/260)
# p countries.select { |country| country['population'].nil? }.map { |country| country['name'] }
 
# 1 What is the population of the country with the most people? Yes, we know it’s China, but just how many people lived there in 1996?
# China
# 1 210 004 956
countries = (doc / :country)
china = countries.max_by { |country| country[:population].to_i }
puts china[:name]
puts china[:population].reverse.chars.each_slice(3).map(&:join).join(' ').reverse
 
puts
# 2 What are the five countries with the highest inflation rates, and what were those rates in 1996?
# {"Belarus"=>244.0, "Turkey"=>94.0, "Azerbaijan"=>85.0, "Malawi"=>83.3, "Yemen"=>71.3}
 
cc = countries.dup
p 5.times.with_object({}) { |_,h|
c = cc.delete cc.max_by { |c| c[:inflation].to_f }
h[c[:name]] = c[:inflation].to_f
}
 
p countries.sort_by { |country| - country[:inflation].to_f }[0...5].each_with_object({}) { |c,h| h[c[:name]] = c[:inflation].to_f }
 
#max = Float::INFINITY
#countries.inject([]) { |best, country|
#}
 
puts
# 3 What are the six continents in the file and which countries belong to which continent? Can you also produce them in alphabetical order?
# ["Europe", "Asia", "North America", "Australia/Oceania", "South America", "Africa"]
 
p continents = (doc / :continent).map { |continent| continent[:name] }
puts
countries_by_continent = countries.each_with_object(Hash.new { |h,k| h[k] = [] }) { |country,h|
h[country[:continent]] << country[:name]
}
#p Hash[countries_by_continent.sort_by { |continent, countries| countries.sort and continent }]
 
puts
p Hash[countries.group_by { |country| country[:continent] }.map { |continent,countries| [continent,countries.map { |c| c[:name] }] }.sort_by { |continent, countries| countries.sort and continent }]
parse.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
# encoding: utf-8
 
# 1 What is the population of the country with the most people? Yes, we know it’s China, but just how many people lived there in 1996?
# 2 What are the five countries with the highest inflation rates, and what were those rates in 1996?
# 3 What are the six continents in the file and which countries belong to which continent? Can you also produce them in alphabetical order?
 
require 'nokogiri'
require 'ap'
 
class String
PLURALS = { "country" => "countries" }
NUMBERS = { "three" => 3, "four" => 4, "five" => 5 }
def singularize
PLURALS.key self
end
def convert
case self
when /\A-?\d+\z/; to_i
when /\A-?\d+\.\d+\z/; to_f
when /\A\d{2} \d{2} \d{4}\z/; Time.new *split.reverse
end
end
alias _to_i to_i
def to_i
NUMBERS[self] || _to_i
end
def === node
node[self]
end
def inspect
dup
end
end
 
class Time
def inspect
strftime('%d %B %Y')
end
end
 
class Integer
def inspect
to_s.reverse.chars.each_slice(3).map(&:join).join(' ').reverse
end
end
 
POS_SUPERLATIVES, NEG_SUPERLATIVES = %w[most biggest highest newest], %w[oldest]
SUPERLATIVES = (POS_SUPERLATIVES+NEG_SUPERLATIVES).join '|'
 
def read question, doc
puts question
case question
when /What is the (?<attribute>[\w ]+) of the (?<element>\w+) with the (?:#{SUPERLATIVES})/
attribute, element = $~[:attribute].tr(' ','_'), $~[:element]
best = (doc / element).grep(attribute).max_by { |e| e[attribute].convert }
puts best[:name]
ap best[attribute].convert
when /What are the (?<n>\w+) (?<elements>\w+) with the (?<sup>#{SUPERLATIVES}) (?<attribute>[\w ]+(?=\?)|\w+)/
n, elements, attribute = $~[:n], $~[:elements], $~[:attribute].tr(' ','_')
ap (doc / elements.singularize)
.grep(attribute)
.sort_by { |e| e[attribute].convert }
.tap { |a| a.reverse! if POS_SUPERLATIVES.include?($~[:sup]) }
.take(n.to_i)
.each_with_object({}) { |e,h| h[e[:name]] = e[attribute].convert }
when /What are the \w+ \w+ .+ which (?<elements>\w+) (belong to|has) which (?<group>\w+)/
_ = (doc / $~[:elements].singularize)
. grep($~[:group])
. each_with_object(Hash.new { |h,k| h[k] = [] }) { |e,h| h[e[$~[:group]]] << e[:name] }
_ = Hash[_.sort_by { |group, elements| elements.sort and group }] if question =~ /in alphabetical order/
_.each_pair { |group, elements|
puts " \e[34m#{group.inspect}:\e[0m #{elements.join ', '}"
}
end
puts
end
 
if __FILE__ == $0
doc = Nokogiri open 'cia-1996.xml'
 
read "What is the population of the country with the most people? Yes, we know it’s China, but just how many people lived there in 1996?", doc
read "What are the five countries with the highest inflation rates, and what were those rates in 1996?", doc
#read "What are the six continents in the file and which countries belong to which continent? Can you also produce them in alphabetical order?", doc
 
read "What is the total area of the country with the biggest territory?", doc
read "What is the infant mortality of the country with the highest infant mortality?", doc
 
read "What are the three countries with the highest population growth?", doc
read "What are the three countries with the newest indep date?", doc
read "What are the three countries with the oldest indep date?", doc
read "What are the five countries with the biggest gdp total?", doc
 
#read "What are the different governments and which countries has which government?", doc
end
question.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
# This heavily use method_missing to not have any String
require './parse'
 
class Question
def initialize(&block)
@question = []
instance_exec(&block)
end
def method_missing(meth, *args)
@question << meth
end
def to_s
@question.reverse.join ' '
end
 
def inspect
"#<Question: #{to_s}>"
end
def ask doc
read to_s, doc
end
end
def ask(&block)
Question.new(&block).ask(@doc)
end
 
@doc = Nokogiri open 'cia-1996.xml'
 
ask { What is the population of the country with the most people? }
 
ask { What are the five countries with the highest inflation rates }
 
ask { What are the six continents within the file _and which countries belong to which continent? }
regexp.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 
doc = open 'cia-1996.xml', &:read
 
class Array
def to_h
Hash[self]
end
end
 
# 1 What is the population of the country with the most people? Yes, we know it’s China, but just how many people lived there in 1996?
puts doc.scan(/<country.+? name='(.+?)'.+? population='(\d+)'/m).max_by { |country, population| population.to_i }.join ' '
 
puts
# 2 What are the five countries with the highest inflation rates, and what were those rates in 1996?
 
# p countries.sort_by { |country| - country[:inflation].to_f }[0...5].map.with_object({}) { |c,h| h[c[:name]] = c[:inflation].to_f }
p doc.scan(/<country.+? name='(.+?)'.+? inflation='([\d.]+)'/m).sort_by { |country,inflation| -inflation.to_f }[0...5].to_h
 
puts
# 3 What are the six continents in the file and which countries belong to which continent? Can you also produce them in alphabetical order?
p doc.scan(/<country.+? continent='(.+?)'.+? name='(.+?)'/m)
.group_by(&:first)
.map { |continent,countries| [continent, countries.map(&:last)] }
.sort_by { |continent, countries| countries.sort and continent }.to_h

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.