読者です 読者をやめる 読者になる 読者になる

Happy Numbers

ruby codeeval

CodeEval


設問理解するのに時間が掛かりましたが、下記のようです。

与えられた数字の各桁をそれぞれ2乗しその和を求める。
これを繰り返し最終的に1になった場合は1、そうならない場合は0と表示する。

設問

Description:

A happy number is defined by the following process. Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers, while those that do not end in 1 are unhappy numbers.

Input sample:

The first argument is the pathname to a file which contains test data, one test case per line. Each line contains a positive integer. Each line is in the format: N i.e. a positive integer eg.

1
7
22

Output sample:

If the number is a happy number, print out a 1. If not, print out a 0 eg.

1
1
0

For the curious, here's why 7 is a happy number: 7->49->97->130->10->1. Here's why 22 is NOT a happy number: 22->8->64->52->29->85->89->145->42->20->4->16->37->58->89 ...

やってみた

#!/usr/bin/env ruby

def happy?(n, checked=[])
  return 1 if n == 1
  checked << n
  square_sum = n.to_s.each_char.map{|x| x.to_i**2}.inject(:+)
  return 0 if checked.include? square_sum
  happy?(square_sum, checked)
end

ARGF.lines do |line|
  puts happy?(line.chomp.to_i)
end

参考

RubyでHappy Numbersを解く -CodeEval - hp12c
またもや、なるほど。
whenの条件に*memで配列渡せるのか。
sum_of_sq_digitでややこしい部分を別出しにするのもいいですね。
each_charもcharsと書けると。

def sum_of_sq_digit(n)
  "#{n}".chars.map { |ch| ch.to_i**2 }.inject(:+)
end

def happy?(n, mem=[])
  case res = sum_of_sq_digit(n)
  when 1
    1
  when *mem
    0
  else
    mem << res
    happy?(res, mem)
  end
end