PDA

View Full Version : [SOLVED] Ruby block



rye_
March 23rd, 2008, 05:46 PM
(1..(str = (2**1000).to_s).length).each {|x| ans = str[x].to_i unless defined? ans #operator# puts ans += str[x] if defined? ans }


hi,

ruby experts. what can I replace #operator# with to make this code work.

Thanks in advance.

Ryan

mssever
March 23rd, 2008, 07:10 PM
Wow. That's some write-only code! I can't tell just what you're trying to do, and you didn't say. Let's see...

str = (2 ** 1000).to_s
1.upto(str.length) do |x|
ans = str[x].to_i unless defined? ans #operator#
puts ans += str[x] if defined? ans
endDoes this refactoring so far do the same thing?

What are you trying to accomplish? What is #operator# supposed to do?

defined? is not a standard method. If you've created it, then you need to explain what it does. Or are you looking for the Object#respond_to? method?

You're trying to put so much on a single line that your code is nearly impossible to understand. (I'm pretty sure the code you posted contains one or more syntax errors.) You're writing Ruby, not Perl. Don't do so much on one line!

rye_
March 23rd, 2008, 08:20 PM
thanks for the reply mssever.

1) defined?

despite its odd syntax, it is a standard method. try this in irb;
puts "rye_ is correct, make him the king!" unless defined? b

2) what am I trying to do?
this is http://projecteuler.net/ prob 16 (I think)

what I'm trying to do is add together the individual digits that make up 2**1000. (and do it on one line)

within the code, #operator# is some kind of comma, or list operator (not sure what ruby uses) to let me define to if conditionals on that one line.

Wybiral
March 23rd, 2008, 08:34 PM
Is there a summation function?

In Python, it would look like this:


sum(int(c) for c in str(2 ** 1000))


I'm not sure if Ruby has generator expressions or a summation builtin though.

mssever
March 23rd, 2008, 08:44 PM
1) defined?

despite its odd syntax, it is a standard method.
Despite how much I like Ruby (it's usually my language of choice), this is the annoying part. You're right. defined? is part of standard Ruby. But it isn't documented anywhere (I looked in ri and on ruby-doc.org). It's a method that might occasionally come in handy...

what I'm trying to do is add together the individual digits that make up 2**1000. (and do it on one line)

within the code, #operator# is some kind of comma, or list operator (not sure what ruby uses) to let me define to if conditionals on that one line.

You're probably looking for a semicolon (although it technically isn't one line anymore). But even then, your code has other bugs. For example, strings are indexed beginning with 0.

Also, you don't need to use defined? at all, or test whether your variable is defined; just make sure it is before entering the block. If you feel you must test whether the variable is defined, consider the ternary operator:
a = (condition) ? do_if_true : do_if_false

Really, though, trying to restrict yourself to one line is a Bad Thing; it makes your code nearly unreadable (and hard to debug), and you don't gain a single thing from it.

a9bejo
March 23rd, 2008, 08:46 PM
Is there a summation function?


No, but in smalltalk-like languages like Ruby, you can use the inject method on an object to do this:


sum = [1,2,3,4].inject{|a,b| a+b}

mssever
March 23rd, 2008, 08:47 PM
Is there a summation function?

In Python, it would look like this:


sum(int(c) for c in str(2 ** 1000))
I'm not sure if Ruby has generator expressions or a summation builtin though.

Good thought. I don't know Ruby's math capabilities very well, since I'm not much of a math person. Where Python uses list comprehensions or generator expressions, Ruby uses blocks.

Wybiral
March 23rd, 2008, 08:51 PM
No, but in smalltalk-like languages like Ruby, you can use the inject method on an object to do this:


sum = [1,2,3,4].inject{|a,b| a+b}


OK, so "inject" is the functional "reduce"?

a9bejo
March 23rd, 2008, 08:55 PM
OK, so "inject" is the functional "reduce"?

exactly

rye_
March 23rd, 2008, 08:57 PM
funnily enough inject was my first though too.

something like; (which by the way is still erronous)

puts (0...(str = (2**2).to_s).length).inject(0) {|x, inj| puts x ; inj+=str[x].to_i }

It's just I often like to try out painful ways of doing things as a learning excercise

rye_
March 23rd, 2008, 08:59 PM
thanks for the semicolon suggestion msever.
I don't think I ever knew about that.

a9bejo
March 23rd, 2008, 09:01 PM
Edit: ...nonesense....

mssever
March 23rd, 2008, 09:01 PM
EDIT: This is wrong; see Wybiral's code, which is a correct version of what I was trying.

Wybiral
March 23rd, 2008, 09:07 PM
exactly

OK, does this look like a roughly equivalent Ruby version of the Python code I posted?


puts (2 ** 1000).to_s.split(//).inject{|a, b| a.to_i + b.to_i}

I didn't know how else to reduce the string, so I split it into an array (I don't program in Ruby, so I'm just going by what I've seen).

EDIT:

I guess technically it's more like this Python code:


print reduce(lambda a, b: int(a) + int(b), str(2 ** 1000))

mssever
March 23rd, 2008, 09:13 PM
OK, does this look like a roughly equivalent Ruby version of the Python code I posted?


puts (2 ** 1000).to_s.split(//).inject{|a, b| a.to_i + b.to_i}
I didn't know how else to reduce the string, so I split it into an array (I don't program in Ruby, so I'm just going by what I've seen).
You're right; My code above is wrong.

rye_
March 23rd, 2008, 09:15 PM
puts (0...(str = (2**1000).to_s).length).inject(0) {|inj, x| inj+=str[x..x].to_i }

That does it

I like the idea of using split. I'll have a play with that.

ps anyone know of any good ruby software whos sourcecode would be good for looking over, and eventually some of US could contribute?

Edit: The reason my previous post's code failed was based on my assumption of how strings behave when accessed as arrays. it seems array[2..2] is different to array[2] (just thought I'd post this)

a9bejo
March 23rd, 2008, 09:23 PM
I like the idea of using split. I'll have a play with that.


Since Ruby 1.9, you can use each_char instead of split. Same result, but more readable. So Wybiral's version becomes:



(2 ** 1000).to_s.each_char.inject{|acc, x| acc.to_i + x.to_i}

rye_
March 23rd, 2008, 09:25 PM
nicely done a9bejo.
All hail YARV
where did you come across that one?

a9bejo
March 23rd, 2008, 09:42 PM
nicely done a9bejo.

where did you come across that one?

Ruby has become a very important tool for me, so I follow the development of the language. Before 1.9, There were various issues with the string class: For example, you had to use this split(//) - hack to get a list of characters, or



"123"[0]


would return 49 (the ascii code of the first char). And, most annoying: Unicode was completely broken.

1.9 is only an experimental release, but it fixes all these issues.