1

I have an array:

[1,2,3,4,5,6,7,8,9,10]

and I need to count three separate things.

1) All values less than or equal to 6.

2) All values equal to 7 or 8.

3) All values greater than 8.

What is the best way to do this without counting individual values and adding them all together?

2
  • You mean add, or count frequency? Commented Oct 12, 2013 at 3:50
  • loop through the array once. And do all the operations in that. Commented Oct 12, 2013 at 3:53

4 Answers 4

3

Use Enumerable#count with a block.

[1,2,3,4,5,6,7,8,9,10].count { |val| val <= 6 }
[1,2,3,4,5,6,7,8,9,10].count { |val| val == 7 || val == 8 }
[1,2,3,4,5,6,7,8,9,10].count { |val| val > 8 }
Sign up to request clarification or add additional context in comments.

3 Comments

Loop through three times ??
@0v3rc10ck3d There is more than one way to do it.
of course more than one way. Wouldn't the fastest/ most efficient be the most interesting way ;)
1
arr = [1,2,3,4,5,6,7,8,9,10]

arr.select {|e| e <= 6}.size
#=> 6

arr.select {|e| e == 7 || e == 8}.size 
#=> 2

arr.select {|e| e > 8}.size 
#=> 2

1 Comment

This seems to be the cleanest way to find the values I need. Thanks!
0

How about this:

>> hash = Hash.new(0)
>> arr = [1,2,3,4,5,6,7,8,9,10]
>> arr.each { |e| hash[(e-7.5).truncate<=>0]+=1 }
>> hash
=> {-1=>6, 0=>2, 1=>2}

Or even more succinct:

>> arr = [1,2,3,4,5,6,7,8,9,10]
>> arr.each_with_object(Hash.new(0)) { |e,h| h[(e-7.5).truncate<=>0]+=1 }
=> {-1=>6, 0=>2, 1=>2}

6 Comments

These posts are pretty eye opening....I'm new to ruby and seeing all of the many ways to get something done is incredible.
Clever! And, of course, .values => [6,2,2]. You could also write the block as {|e,h| h[(e+1)/2-4<=>0]+=1}.
@CarySwoveland, I believe the order of .values is undefined. If an array is required, we should probably use .values_at(-1,0,1) to make it explicit, or .values_at(*-1..1) if we were being clever :-)
nice use of integer division btw
I believe we are OK with v1.9+, as now "Hashes enumerate their values in the order that the corresponding keys were inserted"). BTW, nice use of values_at.
|
0

More interesting, imo, is to answer @Luigi's three questions with a single statement (containing no semicolons). Here are two ways to do it:

a = [1,2,3,4,5,6,7,8,9,10]

a.inject([0,0,0]) {|arr,i| [arr[0]+(i<7 ? 1:0), arr[1]+((i>6 and i<9) ? 1:0), arr[2]+(i>8 ? 1:0)]}
a.slice_before(7).to_a.map {|arr| arr.slice_before(9).to_a}.flatten(1).map(&:size)
    # => [6, 2, 2]

Edit: another, inspired by @staafl's answer:

arr.group_by {|e| (e+1)/2-4<=>0}.values.map(&:size)

Can you suggest others?

Comments

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.