5 Replies - 420 Views - Last Post: 14 March 2019 - 06:15 PM Rate Topic: -----

#1 Gh05t_97   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 10
  • Joined: 11-March 19

Iteration of hashes inside arrays.

Posted 13 March 2019 - 07:11 AM

I basically want to count each element in the array. The array itself consists of separate hashes. I have already done that but I could also use some improvements on the code. I also want to count the the number of times each element appears in the hashes however I don't know how to do that. Appreciate any help. The code is below.

my_array = [{:name => "blake"}, {:name => "blake"}, {:name => "ashley"}]
#EXPECTED RESULT {:name => "blake", :count => 2}, {:name => "ashley", :count => 1}
#BONUS: Count the number of times each element appears inside the hash
# so the output should have the number of times the :names, "blake" and "ashley" element appears

def getOccurances(array)
  b = Hash.new(0)
  array.each do |v|
    b[v] += 1
  end 
  
  b.each do |k,v|
    puts "#{k}: #{v}"
  end
end
    
getOccurances(my_array)
# output
# => {:name=>"blake"}: 2
#=> {:name=>"ashley"}: 1


Is This A Good Question/Topic? 0
  • +

Replies To: Iteration of hashes inside arrays.

#2 andrewsw   User is online

  • never lube your breaks
  • member icon

Reputation: 6819
  • View blog
  • Posts: 28,250
  • Joined: 12-December 12

Re: Iteration of hashes inside arrays.

Posted 13 March 2019 - 07:36 AM

Isn't that code already doing what you describe? It produces the counts 2 and 1 that you expect?
Was This Post Helpful? 0
  • +
  • -

#3 Gh05t_97   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 10
  • Joined: 11-March 19

Re: Iteration of hashes inside arrays.

Posted 13 March 2019 - 07:39 AM

View Postandrewsw, on 13 March 2019 - 07:36 AM, said:

Isn't that code already doing what you describe? It produces the counts 2 and 1 that you expect?


Yes it does, but I want to include the {:count} symbol with the actual count inside the outputting hashes too
Was This Post Helpful? 0
  • +
  • -

#4 andrewsw   User is online

  • never lube your breaks
  • member icon

Reputation: 6819
  • View blog
  • Posts: 28,250
  • Joined: 12-December 12

Re: Iteration of hashes inside arrays.

Posted 13 March 2019 - 08:30 AM

I am not a Rubyist but I have some thoughts for you to approach this.

You have already constructed a hash that contains the unique names and counts. You could create a new, empty, array and iterate the hash; for each key you are creating an object with properties :name and :count (I don't know what Ruby would call these things) that you would then push into the array.
Was This Post Helpful? 0
  • +
  • -

#5 NeoTifa   User is offline

  • NeoTifa Codebreaker, the Scourge of Devtester
  • member icon





Reputation: 4574
  • View blog
  • Posts: 19,278
  • Joined: 24-September 08

Re: Iteration of hashes inside arrays.

Posted 13 March 2019 - 10:49 AM

Have a results array containing hashes. When iterating through the data, check if the array has a hash with name key that matches. If it does, increment count, if not then push a new hash.

results << { name: data['name'], count: 1 } or whatever.
Was This Post Helpful? 0
  • +
  • -

#6 BobRodes   User is offline

  • Product Manager
  • member icon

Reputation: 603
  • View blog
  • Posts: 3,085
  • Joined: 19-May 09

Re: Iteration of hashes inside arrays.

Posted 14 March 2019 - 06:15 PM

Andrew's on the right track. You've done a good job of rolling up the hashes and getting counts. But you now need to format them the way that you want them. Since your result has an entire hash for a key, and is value is a count, what you need to do from there is get the count inside the hash. So:
def getOccurrences(array)
  h_counts = array.each_with_object(Hash.new(0)) { |v, h| h[v] += 1 }
  # p h_counts
  # gets
  h_counts.each_with_object([]) do |v, a| 
    v[0][:count] = v[1]
    a << v[0]
  end
end


Uncomment lines 3 and 4 to see what the result of your accumulator is. I've just done a one-line version of it; it's essentially the same thing that you've done with your each method.

For the next bit on line 5, v is an array, with the key as the first element (in this case, your hash — a key usually isn't a hash; it's usually a symbol, but it can be anything and is a hash in this case). The second element is the value, which we want to add to your hash. So, we add the value in the second element to the hash, with the key of :count, which the hash quite helpfully creates for you automatically since there isn't one. Now, a is the array that we're passing in as an argument. That's how each_with_object works. (You could create an array outside the block, use each, and push values onto that as well, but this is cooler.) So then, the each_with_object method returns the array that we passed in, now nicely populated with what you want.

An even cooler thing that you can do is called "array destructuring," which you can use to make a slight modification that improves readability. Now, when you use each_with_object, the first block argument is the current value from the method call, and the second one is the object that you pass in as an argument to the method. Again, remember that the key to our h_counts hash is itself a hash. So when we use each_with_object, the first block argument is an array with two elements; the first one is the key and the second one is the value. So, in this case, if we call the first argument v, v[0] is the hash key and v[1] is the hash value. As you can see from the last bit of code. But you can also break them apart and give each of them a variable, like this:
 
def getOccurrences(array)
  h_counts = array.each_with_object(Hash.new(0)) { |v, h| h[v] += 1 }
  h_counts.each_with_object([]) do |(h, v), a| 
    h[:count] = v 
    a << h
  end
end


Notice that on line 3, I've replaced the v with an (h, v). If a block variable is an array, you can break it apart by putting multiple variables in parentheses like this. That's array destructuring.

In this case, the first array element will be assigned to h (our hash), and the second one to v (the value we want to add to our hash as :count). So, now we get to do what we want without messing around with array indexes.

Again, it helps a lot to print out values using p, followed by gets, which stops and waits for you to press a key. You can then examine things and get a better idea of what's gong on.

This post has been edited by BobRodes: 14 March 2019 - 06:31 PM

Was This Post Helpful? 1
  • +
  • -

Page 1 of 1