3

How would I count the total number of characters in an array of strings in Ruby? Assume I have the following:

array = ['peter' , 'romeo' , 'bananas', 'pijamas']

I'm trying:

array.each do |counting|
   puts counting.count "array[]"
end

but, I'm not getting the desired result. It appears I am counting something other than the characters.

I searched for the count property but I haven't had any luck or found a good source of info. Basically, I'd like to get an output of the total of characters inside the array.,

2
  • You initial problems are rooted in the fact you are dealing with an Array object which contains a collection of String objects. Unlike C and a number of other languages, a String is not an Array of characters. Commented Feb 22, 2013 at 1:28
  • If you will be writing a significant amount of Ruby, I highly recommend picking up The Ruby Way (amazon.com/The-Ruby-Way-Second-Edition/dp/0672328844) and Eloquent Ruby (amazon.com/Eloquent-Ruby-Addison-Wesley-Professional-Series/dp/…). These are books to be read in bites, not studied. Read and re-read them. And then find some Ruby code to read and savor. Commented Feb 22, 2013 at 1:30

5 Answers 5

9

Wing's Answer will work, but just for fun here are a few alternatives

['peter' , 'romeo' , 'bananas', 'pijamas'].inject(0) {|c, w| c += w.length }

or

['peter' , 'romeo' , 'bananas', 'pijamas'].join.length

The real issue is that string.count is not the method you're looking for. (Docs)

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

2 Comments

These examples are much more idiomatic Ruby than Wing Leong's example.
Actually, you could use string.count with a different approach. The fundamental issue is in understanding that what you have here is an Array object and a collection of String objects. It isn't an array of characters ala C.
5

Or...

a.map(&:size).reduce(:+) # from Andrew: reduce(0, :+)

1 Comment

The reduce doesn’t even need the & and can be simply: reduce(:+). Also note that if the array is empty, this will give nil; change it to reduce(0, :+) to have it return 0 instead.
3

Another alternative:

['peter' , 'romeo' , 'bananas', 'pijamas'].join('').size

Comments

2

An interesting result :)

>> array = []
>> 1_000_000.times { array << 'foo' }
>> Benchmark.bmbm do |x|                                          
>>   x.report('mapreduce') { array.map(&:size).reduce(:+) }       
>>   x.report('mapsum') { array.map(&:size).sum }                 
>>   x.report('inject') { array.inject(0) { |c, w| c += w.length } }   
>>   x.report('joinsize') { array.join('').size }                   
>>   x.report('joinsize2') { array.join.size }                      
>> end

Rehearsal ---------------------------------------------
mapreduce   0.220000   0.000000   0.220000 (  0.222946)
mapsum      0.210000   0.000000   0.210000 (  0.210070)
inject      0.150000   0.000000   0.150000 (  0.158709)
joinsize    0.120000   0.000000   0.120000 (  0.116889)
joinsize2   0.070000   0.000000   0.070000 (  0.071718)
------------------------------------ total: 0.770000sec

                user     system      total        real
mapreduce   0.220000   0.000000   0.220000 (  0.228385)
mapsum      0.210000   0.000000   0.210000 (  0.207359)
inject      0.160000   0.000000   0.160000 (  0.156711)
joinsize    0.120000   0.000000   0.120000 (  0.116652)
joinsize2   0.080000   0.000000   0.080000 (  0.069612)

so it looks like array.join.size has the lowest runtime

3 Comments

i just made a curious check to see which runs fastest given a big set of data and presented it here. you're right that this actually falls under premature optmization, but if it can be optimized in less than 5 minutes, then i say do it. (i changed the wording for you.)
I will agree that often clever functional solutions in Ruby create too many objects and can in fact be way too slow. (That's the problem with mapreduce.) At $dayjob, we once reduced some runtime from days to minutes by replacing a single .merge with .merge!.
There is no need of arguing in this particular case. joinsize2 is the best both in efficiency and reliability/readability/maintainability.
1
a = ['peter' , 'romeo' , 'bananas', 'pijamas']

count = 0
a.each {|s| count += s.length}
puts count

4 Comments

If you accumulate values in a each loop, you could try to do it with a map/inject/each_with_object loop.
@oldergod each_with_object likely wouldn’t work here since Numerics are immutable.
@AndrewMarshall I was speaking in a general manner. He should pick the one that fits its case the most.
Ha, I am new to Ruby, so may be this is not best for Ruby =)

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.