1

I'm attempting to sum only the integers in an array that is passed to my function but keep running up against errors. This is what I have right now.

def sum(*x)
    x.each { |i|
        unless i.is_a? Integer
            x.delete_at(x.index(i)) 
        end
    }
    x.inject(:+)
end

I don't know the numbers of items that might be in the array as you can see the splat operator. I then loop through each array item and check if it's an integer. If it isn't, it is deleted. Finally after only integers are left, the array is summed.

However, I keep getting the following error.

No implicit conversion of Fixnum into String (TypeError)

(This error references the line inject is on. Any idea what I'm doing wrong here?

2
  • Aside: if you had only integers and strings (without leading digits) , this would work: x.reduce { |t,e| t+e.to_i }. Add arrays and hashes (and maybe some other objects) and this would work: x.reduce { |t,e| t+e.to_s.to_i } Commented Aug 16, 2014 at 6:36
  • Consider using plural names for collections: x -> xs. Commented Aug 16, 2014 at 8:00

3 Answers 3

7

There is a cute solution for this :-

your_array.grep(Integer).reduce(0, :+)

Thus, implement your method as :

def sum(*x)
  x.grep(Integer).reduce(0, :+)
end

Read #grep to understand how it works.

Returns an array of every element in enum for which Pattern === element. If the optional block is supplied, each matching element is passed to it, and the block’s result is stored in the output array.

Sign up to request clarification or add additional context in comments.

8 Comments

I believe I would have to require something extra to work this though?
@BorisStitnicky Thank you.. Long weekend.. For me.. :-)
You might also want to .reduce( 0, :+ ) for that pesky case where no integers are in the array.
@BorisStitnicky Valid.. argument.. :-)
@tokland, I was referring to Arup's fondness for Enumerable#grep. I've noticed he's posted many answers that use grep in interesting ways, sometimes making use of the fact that it employs ===.
|
2

x.each iterates through each index of the array as it was at the time of method application. Suppose you had x = ["a", "b", "c"]. In the first iteration over x.each, i as in your code is "a" at index 0. Your code deletes this element from x, making it ["b", "c"]. The iteration goes to index 1, and i is now "c" at index 1. Here, the iteration has skipped "b". As a result, the x you intended to have checked includes elements that are not integers, and you get the error in doing inject(:+).

1 Comment

Ahhhh. That makes total sense now!
1

Keep it simple! No need to modify your existing array, just select what you need!

irb(main):001:0> a=[1,2,"a",3]
=> [1, 2, "a", 3]

irb(main):002:0> a.select {|ax| ax.is_a? Integer}.reduce(0, :+)
=> 6

1 Comment

haha this is actually pretty close to what I ended up with. I did some more reading up on Ruby and simplified it down. :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.