[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Struggling with variable arguments to block

Gavin Sinclair

10/24/2003 7:57:00 AM

Hi -talk,

I'm having trouble dealing with a block that yields one parameter but
declares two. I've pasted complete test code below. Basically, I've
defined "sum" on Enumerable that sums the result of yielding each value.
This is for demonstration of the problem only.

When I define it like this

def sum
result = 0
self.each { |elt| result += yield(elt) }
result
end

{1=>2}.sum { |k,v| v } works but gives a warning.
[[1,2]].sum { |a,b| b } is fine.

When I define it like this

def sum
result = 0
self.each { |*elt| result += yield(*elt) }
result
end

{1=>2}.sum { |k,v| v } is fine.
[[1,2]].sum { |a,b| b } gives an error.


Below are the two definitions and a complete test case. In the test case,
the range examples have no problems so are uncommented. Comments are
given in the other cases.

I would really like to avoid the warning associated with the hash in
test_sum1h.

Thanks for any advice,
Gavin

--------------------------------------------------------------------------


module Enumerable
#
# Yield each element and return the (strictly numerical) sum of the
# results. sum1 and sum2 are different implementations.
#

def sum1
result = 0
self.each do |elt|
result += yield(elt)
end
result
end

def sum2
result = 0
self.each do |*elt|
result += yield(*elt)
end
result
end
end


require 'test/unit'

#
# Test case: set up 3 enumerable objects, and try sum1 and sum2 on
# each of them.
#
class TC_Sum < Test::Unit::TestCase
def setup
@r = (1..10) # We'll sum the squares (385)
@a = [ [1,2], [3,4], [5,6] ] # We'll sum the products (44)
@h = { :a => 1, :b => 2, :c => 3 } # We'll sum the values (6)
end

# ======== First implementation

def test_sum1r
puts "test_sum1r"
sum = @r.sum1 { |x| x ** 2 }
assert_equal(385, sum)
end

def test_sum1a
puts "test_sum1a"
sum = @a.sum1 { |x,y| x * y } # Passes.
assert_equal(44, sum)
end

def test_sum1h
puts "test_sum1h"
sum = @h.sum1 { |k,v| v } # Passes, with warning:
assert_equal(6, sum) # multiple values for a block
end # parameter (2 for 1)

# ======== Second implementation

def test_sum2r
puts "test_sum2r"
sum = @r.sum2 { |x| x ** 2 }
assert_equal(385, sum)
end

def test_sum2a
puts "test_sum2a"
sum = @a.sum2 { |x,y| x * y } # Error: no implicit conversion
assert_equal(44, sum) # from nil to integer
end

def test_sum2h
puts "test_sum2h"
sum = @h.sum2 { |k,v| v } # Passes.
assert_equal(6, sum)
end
end




6 Answers

Dan Doel

10/24/2003 8:41:00 AM

0

Which version of ruby are you using?

I copied, pasted and got no errors with the mswin32 1.8.0 build.

- Dan


Gavin Sinclair

10/24/2003 8:56:00 AM

0

Dan wrote:

> Which version of ruby are you using?

Ah, good question.

ruby 1.8.0 (2003-09-01) [i386-cygwin]

> I copied, pasted and got no errors with the mswin32 1.8.0 build.

Thanks for the report. I'll try the very latest version.

Gavin





Robert Klemme

10/24/2003 10:22:00 AM

0


"Gavin Sinclair" <gsinclair@soyabean.com.au> schrieb im Newsbeitrag
news:42460.203.185.214.34.1066957666.squirrel@webmail.imagineis.com...
> Hi -talk,

Nope, c.l.r here. :-)

> I'm having trouble dealing with a block that yields one parameter but
> declares two. I've pasted complete test code below. Basically, I've
> defined "sum" on Enumerable that sums the result of yielding each value.
> This is for demonstration of the problem only.
>
> When I define it like this
>
> def sum
> result = 0
> self.each { |elt| result += yield(elt) }
> result
> end
>
> {1=>2}.sum { |k,v| v } works but gives a warning.
> [[1,2]].sum { |a,b| b } is fine.
>
> When I define it like this
>
> def sum
> result = 0
> self.each { |*elt| result += yield(*elt) }
> result
> end
>
> {1=>2}.sum { |k,v| v } is fine.
> [[1,2]].sum { |a,b| b } gives an error.

[snip]

Could it be that the heart of your problem is, that you're trying to sum
things up that can't be summed up? Consider this:

elems = [ [1,2,3], [10], [23,145,23] ]

elems contains Arrays and there is no such thing as Array#+ - for good
reasons. If you're after the sum, you typically need rather something
like this:

sum = elems.map {|e| extract_a_numeric_value(e)}.inject( 0 ){|c,e|c+e}

Where extract_a_numeric_value is the crucial part.

Just my EUR 0.02...

Regards

robert

ts

10/24/2003 10:40:00 AM

0

>>>>> "R" == Robert Klemme <bob.news@gmx.net> writes:

R> elems contains Arrays and there is no such thing as Array#+

svg% ruby -e 'p [1]+[2]'
[1, 2]
svg%

R> - for good reasons.

which are ?


--

Guy Decoux

Robert Klemme

10/24/2003 11:35:00 AM

0


"ts" <decoux@moulon.inra.fr> schrieb im Newsbeitrag
news:rfcekx2c420.fsf@moulon.inra.fr...
> >>>>> "R" == Robert Klemme <bob.news@gmx.net> writes:
>
> R> elems contains Arrays and there is no such thing as Array#+
>
> svg% ruby -e 'p [1]+[2]'
> [1, 2]
> svg%
>
> R> - for good reasons.
>
> which are ?

:-)

Apparently I wasn't clear enough:

irb(main):002:0> [2]+[3,4]
=> [2, 3, 4]
irb(main):003:0>

That's not the plus Gavin was looking for. His example was about adding
numeric values from arrays. Something whose functionality would resemble
this line:

irb(main):003:0> [[2],[3,4]].map{|e|e[0]}.inject(0){|c,e|c+e}
=> 5
irb(main):004:0>

However, the point was that there were problems with hashes and nested
arrays when used with his defined method sum

def sum
result = 0
self.each { |*elt| result += yield(*elt) }
result
end

My point was that these problems resulted from the attempt to write a
generalized sum method for things that are not easily summed, i.e.,
arrays, which can have differing lengths and can contain arbitrary types
that are not necessarily useful for numerical summing up.

IOW, he is looking for a solution to the yield problem while I suggested,
that the real problem here was an inappropriate approach. Hopefully this
has become clearer now...

Regards

robert

matz

10/24/2003 1:57:00 PM

0

Hi,

In message "Struggling with variable arguments to block"
on 03/10/24, "Gavin Sinclair" <gsinclair@soyabean.com.au> writes:

|I'm having trouble dealing with a block that yields one parameter but
|declares two. I've pasted complete test code below. Basically, I've
|defined "sum" on Enumerable that sums the result of yielding each value.
|This is for demonstration of the problem only.

I smell something wrong. Hmm...<thinking it a while>

I get it. Hash#each should have passed single value to the block,
unlike Hash#each_pair. It will be fixed soon.

matz.
c