2

I have the following:

article_results.keys do |key|
  article_results[key].map! do |a|
    a[:filename] = c.filename
    a[:sitename] = c.site_name
    a
  end
end

As I want to add to each element of each array within the hash dynamically, but for some reason a[:filename] and a[:sitename] are blank when they are used.

So I want to know if I should be using .each instead. Also I guess I'd like to know what's the main difference since they both can be used for side-effects.

I'm adding this as an extra fyi, I'm using ruby 1.8.7 so it would be nice to know how it differs between versions (1.8.7 - 1.9+) as well.

P.s. I know what the difference between .each and .map is, I'm asking specifically about .map!.

Thermatix
  • 2,224
  • 13
  • 36

1 Answers1

0

#map has a bit different semantics for hashes than it has for arrays (and i think it's not very consistent between versions of ruby). in general if you are looking for an array as a result of some operation - #map is your friend, however if you want hash as a result of some operation - you're better off with #reduce:

article_results.reduce({}) do |hash, (key, value)|
  hash.merge(key => value.merge(filename: c.filename,
                                sitename: c.sitename))
end

alternatively if you don't care how "functional" your code is, you can use #each:

article_results.each do |key, value|
  article_results[key].merge!(filename: c.filename,
                              sitename: c.sitename)
end
keymone
  • 7,346
  • 1
  • 23
  • 33
  • I keep forgetting there's a difference between 1.8.7 (which I'm currently forced to use) and 1.9+, I'll add that to the op. reduce looks like inject, is that the same thing? Also, article_results is a hash of arrays of objects with hash like setters & getters to add extra data. – Thermatix Jul 28 '16 at 10:43
  • correct, reduce is alias to inject (or vice versa). it's just a matter of coherent naming - map goes with reduce, inject goes with collect. from code in your question it looks like `artice_results` is hash of hashes (or objects that behave like hashes) so `merge!` should work on them. if it doesn't - just use `[]=` directly. – keymone Jul 28 '16 at 10:53
  • actually if `article_results` is hash of arrays then your `map!` code is correct and you should make sure `c.filename` is valid. and ofc `.keys` doesn't take a block, must be `.keys.each` – keymone Jul 28 '16 at 11:05
  • ah, it's probably becuase I forgot to do a `.each` still, doing `.each` on the hash should be slightly faster as it doesn't have to generate the array of keys each time. – Thermatix Jul 28 '16 at 11:11
  • it is a micro-optimization. code quality and clarity should be your top priority. – keymone Jul 28 '16 at 11:20