0

Say I have an array as such:

array = [["male", 59], ["female", 31], ["unknown gender", 38]] 

The number inside the array is the total number of users by gender. What I need to do is get each element of the array and find the average for each male, female and unknown and put them into a new array that looks like this:

new_array = [["male", 46], ["female", 24], ["unknown gender", 30]] 

Where the 2nd value inside the tuple is the average.

I have tried setting it as such:

new_array = []
sum = 0
array.each do |k,v|
sum += v
new_array << [k,(v/sum)*100]
end

My new array however turns out to be [["male", 100], ["female", 0], ["unknown gender", 0]]

Ive tried a few different things and cannot figure out what Im doing wrong. Any help would be great.

2
  • 2
    I don't see how you would get the second array from the first. Does the first actually have more subarrays? Commented Nov 3, 2014 at 0:12
  • I added an edit above, the numbers inside the first array are the total number of users by gender, I need to create a new array with the average % of the demographics Commented Nov 3, 2014 at 0:16

4 Answers 4

1

There are two issues here.

The first is that you are doing integer division at (v/sum). The result of this is probably not what you expect, so you should turn v into a float: (v.to_f/sum).

The second problem is that you are using the sum variable before it actually contains the sum.

Putting these two together:

array = [["male", 59], ["female", 31], ["unknown gender", 38]] 
new_array = []
sum = 0
# calculating sum before it's used in division below.
array.each { |_, v| sum += v }

array.each do |k, v|
  new_array << [k, ((v.to_f / sum) * 100).round]
end
# => [["male", 46], ["female", 24], ["unknown gender", 30]]
Sign up to request clarification or add additional context in comments.

2 Comments

Thats it, thank you. My goal was trying to make this into a single iteration, Im learning about Big O notation so Im trying to write this in the best possible way, unfortunately it looks like there was no other way then creating 2 separate iterations. Thank you again.
Iteration two times over the same array means O(2n). What is still in O(n) complexity. That is fine, especially because it is unlikely that a list of genders will get huge.
0

You need to do a few things. what is happening now is that sum is 59. v/59 is one on the first iteration. On the second iteration 31/90 == 0 because you are not dividing the sum by the number of iterations. What you really want is 31/45 because 45 is 90/2(2 being the number of iterations)

1) you need to divide the sum by the number of iterations to get the current average.

2) your syntax of

array.each do |k,v|

is misleading because you are not dealing with keys and values but with array indexes.

Comments

0

I would prefer to use more specialised Ruby methods like inject or map instead of the simple each:

array = [['male', 59], ['female', 31], ['unknown gender', 38]] 

total = array.inject(0) { |sum, (_, n)| sum + n }

new_array = array.map { |k, v| [k, ((v.to_f / total) * 100).round] }
#=> [["male", 46], ["female", 24], ["unknown gender", 30]]

Furthermore the ((v.to_f / total) * 100).round part can be extracted into its own method like this:

def percentage(value, total)
  ((value.to_f / total) * 100).round
end

What makes the map more readable:

new_array = array.map { |k, v| [k, percentage(v, total)] }

Comments

0

If you have a choice, I suggest you consider using hashes rather than an arrays and symbols rather than strings:

hash = { male: 59, female: 31, unknown_gender: 38 }
  #=> {:male=>59, :female=>31, :unknown_gender=>38}
tot = hash.values.reduce(:+)
  #=> 128
percents = hash.each_with_object({}) { |(k,v),h| h[k] = (100.0*v/tot).round }
  #=> {:male=>46, :female=>24, :unknown_gender=>30}

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.