ループで繰り返し引いて。丸め誤差の問題でちょっと..整数化してやったほうがいいの?
お釣りをコインとお札で。
#!/usr/bin/env ruby
COINS = {
'PENNY' => 0.01,
'NICKEL' => 0.05,
'DIME' => 0.10,
'QUARTER' => 0.25,
'HALF DOLLAR' => 0.50,
'ONE' => 1.00,
'TWO' => 2.00,
'FIVE' => 5.00,
'TEN' => 10.00,
'TWENTY' => 20.00,
'FIFTY' => 50.00,
'ONE HUNDRED' => 100.00
}
def cash_out(pp, ch)
negative = ->i{ i < 0 }
zero = ->i{ i.zero? }
case ret = round_off(ch - pp)
when negative; :ERROR
when zero; :ZERO
else count_coins(ret)
end
end
def count_coins(ret)
coins = COINS.values
q = []
while ret != 0.0
if ret >= (try=coins.pop)
q << try
ret = round_off(ret - try)
coins.push try
end
end
q.map { |val| COINS.key val }.sort.join(',')
end
def round_off(f, n=2)
(f*10**(n+1)).round/10.0**(n+1)
end
ARGF.lines do |line|
pp, ch = line.split(';').map(&:to_f)
puts cash_out(pp, ch)
end
Double Squaresを残してModerate終了。できそうもない..
Enumeratorをtake_whileして。
指定数までの素数列。
#!/usr/bin/env ruby
def prime?(n)
!(2..n/2).any? { |i| (n%i).zero? }
end
def prime_loop
Enumerator.new { |y| n = 2; loop { y << n if prime?(n); n+=1 } }
end
ARGF.lines do |line|
max = line[/\d+/].to_i
puts prime_loop.take_while { |i| i < max }.join(',')
end
回文になるまでループして。
数字をひっくり返して足すことを繰り返して回文になる回数。
#!/usr/bin/env ruby
def palindrome(num)
"#{num}" == "#{num}".reverse ? num : false
end
def reverse_add(num)
num + "#{num}".reverse.to_i
end
ARGF.lines do |line|
num = line[/-*\d+/].to_i
cnt = 0
begin
num = reverse_add(num)
cnt += 1
end until ret = palindrome(num)
printf "%d %d\n", cnt, ret
end
Array#each_consを使って。
並びの数字の差が3 2 1となってるものをJolly Jumperというらしい。
#!/usr/bin/env ruby
ARGF.lines do |line|
n, *nums = line.scan(/\d+/).map(&:to_i)
seq = nums.each_cons(2).inject([]) { |mem, cons| mem << cons.inject(:-).abs; mem }
puts seq.all? { |i| n-=1; i == n } ? 'Jolly' : 'Not jolly'
end
余計な条件がよくわからない..
数字列中の重複を見つける。
#!/usr/bin/env ruby
ARGF.lines do |line|
next if line.chomp.empty?
n, nums = line.split(';').map { |part| part[/,/] ? part.split(',').map(&:to_i) : part.to_i }
next if nums.size != n or nums.any? { |i| !i.between?(0, n-2) }
nums.sort.inject { |mem, i| mem == i ? puts(i) : mem = i }
end
本気じゃないよね?適当なところで。
メールアドレスの正規表現。
#!/usr/bin/env ruby
def valid_email?(str)
email_regexp = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/
str.match(email_regexp) ? :true : :false
end
ARGF.lines do |line|
puts valid_email?(line.chomp)
end
Array#combinationを使って。
数字列から合計が指定数になる数字のペアを見つける。
#!/usr/bin/env ruby
ARGF.lines do |line|
nums, x = line.split(';').map do |part|
part[/,/] ? part.split(',').map(&:to_i) : part.to_i
end
pairs = nums.combination(2).select { |a, b| a + b == x }
puts pairs.empty? ? :NULL : pairs.map { |pair| pair.join(',') }.join(';')
end
ワンライナーで:)
文字列中のサブ文字列を見つける。
#!/usr/bin/env ruby
ARGF.lines do |line|
line.split(',').map(&:chomp).instance_eval { puts first[/#{last}$/] ? 1 : 0 }
end
10進数を2進数に。
#!/usr/bin/env ruby
puts ARGF.map { |line| line[/\d+/].to_i.to_s(2) }
ループで全組合せを作ってArray#max。
数字の並びにおける連続する数字群の最大値。
#!/usr/bin/env ruby
ARGF.lines do |line|
nums = line.scan(/-*\d+/).map(&:to_i)
candidates = []
begin
nums.inject(0) { |mem, i| candidates << mem += i; mem }
end while nums.shift
puts candidates.max
end
String#countで。
数字の2進表現の1ビットの数。
#!/usr/bin/env ruby
puts ARGF.map { |line| line[/\d+/].to_i.to_s(2).count('1') }
Array#packを使って。
システムのエンディアン。
#!/usr/bin/env ruby
def system_endian
system, big, little = %w(s2 n2 v2).map { |ts| [1,2].pack ts }
case system
when big; :BigEndian
when little; :LittleEndian
end
end
puts system_endian
String#deleteで。
文字列から指定文字を除く。
#!/usr/bin/env ruby
ARGF.lines do |line|
if m = line.match(/^(.*),\s*(\w+)/)
str, scrubs = m.captures
puts scrubs.chars.inject(str) { |s, chr| s.delete chr }
end
end
Enumerable#detectで。
文字列中の繰り返さない最初の文字。
#!/usr/bin/env ruby
ARGF.lines { |line| puts line.chars.detect { |chr| line.count(chr) == 1 } }
いやいやもっと簡単な方法があるはずだ。
バイナリーツリーの共通の親を見つける。
#!/usr/bin/env ruby
class Node
attr_reader :label, :sub
def initialize(label, *sub)
@label = label
@sub = sub
end
end
def node
->label,*sub{ Node.new(label, *sub) }
end
def ancestors(label, tree, mem=[])
ancestor = tree.label
if ancestor == label
mem
else
sub = tree.sub
if sub.empty?
[]
else
sub.map { |s| ancestors(label, s, mem+[ancestor]) }
end
end.flatten
end
def find_lowest_common_ancestor(a, b, tree)
(ancestors(a, tree) & ancestors(b, tree)).last
end
tree = node[30,
node[8,
node[3],
node[20,
node[10],
node[29]
]
],
node[52]
]
ARGF.lines do |line|
a, b = line.scan(/\d+/).map(&:to_i)
puts find_lowest_common_ancestor(a, b, tree)
end
アルファベットの並びにおける位置。
#!/usr/bin/env ruby
ARGF.lines do |line|
*alpha, ns = line.split(/\s/)
if ch=alpha[-ns.to_i]
puts ch
end
end
どうすりゃいいのか。
スタックを実装する。
#!/usr/bin/env ruby
class Stack
def initialize
@stack = []
end
def push(n)
@stack += [n]
end
def pop
@stack[-1].tap { @stack = @stack[0..-2] }
end
end
ARGF.lines do |line|
nums = line.scan(/\-?\d+/).map(&:to_i)
st = Stack.new
nums.each { |n| st.push n }
loop do
print "#{st.pop} "
break puts unless st.pop
end
end
Array#-を使って。
文字列がパングラムか判定する。
#!/usr/bin/env ruby
def pangram?(str)
compo = str.scan(/\w/).map(&:downcase).uniq.sort
deficits = [*'a'..'z'] - compo
deficits.empty? ? 'NULL' : deficits.join
end
puts ARGF.map { |line| pangram?(line) }
ループを使って。綺麗にかけない..
文字の並び中の繰り返しを見つける。
#!/usr/bin/env ruby
def find_cycles(nums)
ns = nums.dup
while top = ns.shift
if pos = ns.index(top)
first = ns[0...pos]
second = ns[(pos+1)..(pos+first.size)]
return [top, *first].join(' ') if first == second
end
end
nil
end
ARGF.lines do |line|
nums = line.scan(/\d+/).map(&:to_i)
if cycle = find_cycles(nums)
puts cycle
end
end
ワンライナーで:)
先頭行の数だけ後続行から最長文字列を選ぶ。
#!/usr/bin/env ruby
puts ARGF.map(&:chomp).instance_eval { n=shift.to_i; sort_by{ |l| -l.size }.take(n) }