Struggling with variable arguments to block

G

Gavin Sinclair

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
 
D

Dan Doel

Which version of ruby are you using?

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

- Dan
 
G

Gavin Sinclair

Dan said:
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
 
R

Robert Klemme

Gavin Sinclair said:
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
 
T

ts

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 ?
 
R

Robert Klemme

ts said:
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
 
Y

Yukihiro Matsumoto

Hi,

In message "Struggling with variable arguments to block"

|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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top