Eloquent Ruby Kaprekar's Number

Which way is the eloquent ruby way to write this algorithm?

Kaprekar Number

9 is a Kaprekar number since
9 ^ 2 = 81 and 8 + 1 = 9

297 is also Kaprekar number since
297 ^ 2 = 88209 and 88 + 209 = 297.

In short, for a Kaprekar number k with n-digits, if you square it and
add the right n digits to the left n or n-1 digits, the resultant sum is
k.

!Spoiler Below!

way one

def kaprekar?(k)
ks = k**2
lenf = (ks.to_s.length)-1
lenh = (ks.to_s.length / 2) - 1
a = ks.to_s[0…lenh].to_i
b = ks.to_s[lenh+1…lenf].to_i
k == (a+b)
end

way two

def kaprekar?(k)
a = (k2).to_s[0…((((k2).to_s.length) / 2) - 1)].to_i
b = (k2).to_s[(((((k2).to_s.length) / 2) -
1)+1)…(((k**2).to_s.length)-1)].to_i
k == (a+b)
end

way three

def kaprekar?(k)
k == ((k2).to_s[0…((((k2).to_s.length) / 2) -
1)].to_i)+((k2).to_s[(((((k2).to_s.length) / 2) -
1)+1)…(((k**2).to_s.length)-1)].to_i)
end

def simple_test(i)
if kaprekar?(i) == true then p “success on #{i}” else “fail on #{i}”
end
end

simple_test(9)
simple_test(297)

All three pass my tests, but which of the three would be considered the
most eloquent written ruby way? As in, which would be consider best
style-wise? The first takes up the most lines, but uses less nesting.
The last uses only one line but uses lots of nesting.

On Thu, May 30, 2013 at 6:59 PM, Alphonse 23 [email protected]
wrote:

In short, for a Kaprekar number k with n-digits, if you square it and
a = ks.to_s[0…lenh].to_i
end
end

Posted via http://www.ruby-forum.com/.

This is the way I’d do it:

def kaprekar?(k)

n = k.to_s.length
ks = (k*k).to_s
l = ((n-1)-(n%2))
l = 0 if l < 0

nl = ks[0…l].to_i
nr = ks[-n…-1].to_i

k == nl + nr

end

I could not say if that’s more rubyist or not, though. I imagine there
is probably a way to use map/reduce and pass a block or something :wink:

On Thu, May 30, 2013 at 9:08 PM, tamouse mailing lists
[email protected] wrote:

lenh = (ks.to_s.length / 2) - 1
k == (a+b)
if kaprekar?(i) == true then p “success on #{i}” else “fail on #{i}”

l = ((n-1)-(n%2))
I could not say if that’s more rubyist or not, though. I imagine there
is probably a way to use map/reduce and pass a block or something :wink:

Well, that will teach me not to test more thoroughly.

def kaprekar?(k)

n = k.to_s.length
ks = (k*k).to_s
l = ((n-1)-(ks.length%2))
l = 0 if l < 0

nl = ks[0…l].to_i
nr = ks[-n…-1].to_i

if k == nl + nr
puts “k=#{k}, n=#{n}, ks=#{ks}, l=#{l}, nl=#{nl}, nr=#{nr},
nl+nr=#{nl+nr}”
true
else
false
end

end

and some tests:

irb(main):056:0> 0.upto(1000).each {|i| puts “#{i} is kaprekar” if
kaprekar?(i)}
k=0, n=1, ks=0, l=0, nl=0, nr=0, nl+nr=0
0 is kaprekar
k=9, n=1, ks=81, l=0, nl=8, nr=1, nl+nr=9
9 is kaprekar
k=45, n=2, ks=2025, l=1, nl=20, nr=25, nl+nr=45
45 is kaprekar
k=55, n=2, ks=3025, l=1, nl=30, nr=25, nl+nr=55
55 is kaprekar
k=99, n=2, ks=9801, l=1, nl=98, nr=1, nl+nr=99
99 is kaprekar
k=297, n=3, ks=88209, l=1, nl=88, nr=209, nl+nr=297
297 is kaprekar
k=703, n=3, ks=494209, l=2, nl=494, nr=209, nl+nr=703
703 is kaprekar
k=999, n=3, ks=998001, l=2, nl=998, nr=1, nl+nr=999
999 is kaprekar

Alphonse 23 wrote in post #1110725:

In short, for a Kaprekar number k with n-digits, if you square it and
add the right n digits to the left n or n-1 digits, the resultant sum is
k.

Hi,

Yes, Kaprekar number is good to be an exercise in creating a (Ruby)
code, but after googling it, what are the practical applications for
Kaprekar numbers?

Best regards,

Bill

P.S. Forgive me, if the discussion is rather off-topic from Ruby.

Am 31.05.2013 01:59, schrieb Alphonse 23:

In short, for a Kaprekar number k with n-digits, if you square it and
a = ks.to_s[0…lenh].to_i
end
end
end

simple_test(9)
simple_test(297)

All three pass my tests, but which of the three would be considered the
most eloquent written ruby way? As in, which would be consider best
style-wise? The first takes up the most lines, but uses less nesting.
The last uses only one line but uses lots of nesting.

To me, as long as there are no performance considerations involved,
generally the best version is the one I understand in the shortest
amount of time. Cryptic one-liners might be nice as brain-teasers
but not for real applications.

Also, I highly prefer telling variable names over ks, a, b, etc.
Why not use square, digits, left_number, … or similar?
IMO that make a big difference in readability.

On Thu, May 30, 2013 at 6:59 PM, Alphonse 23 [email protected]
wrote:

In short, for a Kaprekar number k with n-digits, if you square it and
a = ks.to_s[0…lenh].to_i
end
end

Posted via http://www.ruby-forum.com/.

I’d write it like this:

def kaprekar?(num)
return false if num.zero? || num.to_s =~ /^10+$/ # IDK why 0 and 10…
are
disallowed when 1 is allowed, but w/e
square = (num * num).to_s
midpoint = square.size / 2
(0…midpoint).any? do |separation_index|
first = square[0…separation_index].to_i
second = square[separation_index…-1].to_i
num == first + second
end
end

RSpec.configure { |config| config.fail_fast = true }

numbers taken from Kaprekar number - Wikipedia

describe ‘kaprekar number’ do
def check_kaprekars(kaprekars)
(0…kaprekars.last).select { |n| kaprekar? n }.should == kaprekars
end

example ‘quick match’ do
check_kaprekars [1, 9, 45, 55, 99, 297, 703, 999]
end

example ‘medium match’ do
check_kaprekars [1, 9, 45, 55, 99, 297, 703, 999 , 2223, 2728, 4879,
4950, 5050, 5292, 7272, 7777, 9999]
end

example ‘these should match’ do
check_kaprekars [1, 9, 45, 55, 99, 297, 703, 999 , 2223, 2728, 4879,
4950, 5050, 5292, 7272, 7777, 9999 , 17344, 22222, 38962, 77778, 82656,
95121, 99999, 142857, 148149, 181819, 187110, 208495, 318682, 329967,
351352, 356643, 390313, 461539, 466830, 499500, 500500, 533170]
end
end

Admin T. wrote in post #1110741:

Hi,

Yes, Kaprekar number is good to be an exercise in creating a (Ruby)
code, but after googling it, what are the practical applications for
Kaprekar numbers?

There isn’t any, I believe. Though there could be a use for them in the
future. I used Kaprekar’s number because it’s simple. This was just an
exercise in writing ruby code, specifically how to write good readable
“eloquent” code.

Peter H. wrote in post #1110774:

You never use ks as it is you always use ks.to_s so we might was well go
with that and make is easier to read.
The line breaks make it more obvious as to the steps you are taking.

Again it is just a personal preference.

Finally the simple_test code does not work for failures.

Woops, sorry about that. Yes, the simple_test code is really bad. I’m
still learning how to use Rspec.

After reviewing everyone else’s algorithms here’s my new version. I
believe this is the most readable and rubyist like.

def kaprekar?(num)
return false if num.zero?

num_square = (num**2).to_s
num_len = num_square.length
midpoint = (num_len / 2)-1

left = num_square[0…midpoint].to_i
right = num_square[midpoint+1…-1].to_i

num == left + right
end

p kaprekar?(9)
p kaprekar?(297)

Now I need to go learn Rspec…

For me 2 and 3 are unreadable, not to mention overly complicated. I
would
go with a modified version of 1

def kaprekar?(k)
ks = (k**2).to_s
lenks = ks.length

lenf = (lenks)-1
lenh = (lenks/2)-1

a = ks[0…lenh].to_i
b = ks[lenh+1…lenf].to_i

k == (a+b)
end

You never use ks as it is you always use ks.to_s so we might was well go
with that and make is easier to read.
The line breaks make it more obvious as to the steps you are taking.

Again it is just a personal preference.

Finally the simple_test code does not work for failures.

Am 31.05.2013 22:04, schrieb Alphonse 23:

Now I need to go learn Rspec…

There is also minitest/spec, you should have a look at that, too.

Your new version is much clearer. But I will nitpick anyway :slight_smile:

midpoint = (num_len / 2)

left = num_square[0…midpoint].to_i
right = num_square[midpoint…-1].to_i

There is no need to do the -1 / +1 thing by using the … range
operator.

However the fact that it is … rather than … is easy to overlook when
reading code so I can understand peoples reluctance to use it.

Alphonse 23 wrote in post #1110829:

There isn’t any, I believe. Though there could be a use for them in the
future. I used Kaprekar’s number because it’s simple. This was just an
exercise in writing ruby code, specifically how to write good readable
“eloquent” code.

Hi,

Thank you for replying. How about some exercises that are related to
prime numbers? I think at least, in theory, you can use it with
cryptography (in theory, not in a practical app); but there are other
various problems/exercises that deal with prime numbers. Just a little
thought.

Best regards,

Bill

Your requirements seem to be different than the definition that I read.
See
Josh’s solution and link.
For example, you are missing 4879.

Anyway, FWIW.

def try1(n)
s,a = n.to_s.size,[]
(s…s*2).each{|y| a << (n 2)/(10y)+(n2)%(10y)}
a.include?(n)
end

arr = []
(1…100_000).each{|x|arr << x if try1(x)}
p arr #> [1, 9, 45, 55, 99, 297, 703, 999, 2223, 2728, 4879, 4950, 5050,
5292, 7272, 7777, 9999, 17344, 22222, 38962, 77778, 82656, 95121, 99999]

Harry

Peter H. wrote in post #1110835:

Your new version is much clearer. But I will nitpick anyway :slight_smile:

midpoint = (num_len / 2)

left = num_square[0…midpoint].to_i
right = num_square[midpoint…-1].to_i

There is no need to do the -1 / +1 thing by using the … range
operator.

However the fact that it is … rather than … is easy to overlook when
reading code so I can understand peoples reluctance to use it.

That doesn’t compile for me.

this does though:

def kaprekar?(num)
return false if num.zero?

num_square = (num**2).to_s
num_len = num_square.length
midpoint = (num_len / 2)

left = num_square[0…midpoint-1].to_i
right = num_square[midpoint…-1].to_i

num == left + right
end

Am 01.06.2013 15:21, schrieb Harry K.:

def try2(n)
s, q = n.to_s.size, nn
(s…s
2).each do|x|
y = 10**x
return true if n == q/y+q%y
end
false
end

OP was asking for “eloquent” solutions…

This should be faster than my previous solution (if it matters).

def try2(n)
s, q = n.to_s.size, nn
(s…s
2).each do|x|
y = 10**x
return true if n == q/y+q%y
end
false
end

Harry

I packed everyone’s solution up with tests and benchmarks:

On Sat, Jun 1, 2013 at 9:51 AM, [email protected] wrote:

end

OP was asking for “eloquent” solutions…

This may not be eloquent ruby, but it certainly is sublime. Only patch
would be to test if n is a non-negative Integer.

tamouse mailing lists wrote in post #1110924:

I packed everyone’s solution up with tests and benchmarks:
GitHub - tamouse/kaprekar_kata: A nice ruby kata finding Kaprekar numbers

nice. a lot of fun. Now I think I know why people like Rspec so much.