Cleaner way to display hash in ruby
Suppose I need to do a trivial task for each element of a Hash
, eg. increase its value by 1
or change the value to an array containing this value. I did it like this:
hash.map{ |k, v| [k, v+1] }.to_h
v+1
- just an example, it could be anything.
Is there a cleaner way to do this? I don't really like mapping a hash to an array of arrays of size 2 and then remembering to convert it back to a hash again.
An example of what could be nicer:
hash.hash_map{ |v| v+1 }
Thus, some things like string conversion ( to_s
) can be simplified to
hash.hash_map(&:to_s)
Clarification of duplication: I'm not looking for Hash[...]
or .to_h
, I'm asking if anyone knows of a more compact and cleaner solution.
source to share
This is how the Ruby framework works. There Enumerable
is one method map
that doesn't know anything about hashes or arrays or lists or sets or trees or streams or anything else you can think of. All he knows is a named method each
that will yield
have one element per iteration. What is it.
Note that this is the same as the Java and .NET collection frameworks. All operations with collections always return the same type: in .NET, that IEnumerable
in the Ruby, Array
.
Another design approach is that collection operations are stored in the type, i.e. displaying a set will result in a set, etc. This is how Smalltalk does it, for example. However, in Smalltalk, but there it is achieved by copying and pasting almost the same methods into every collection. That is, if you want to implement your own collection, in Ruby you need to implement each
it and you get everything else for free, whereas in Smalltalk you have to implement each separate collection method separately. (In Ruby, this will be over 40 methods.)
Scala is the first language that managed to provide a collection structure with type persistence without duplicating code, but until Scala 2.8 (released in 2010) to figure it out. (The idea of builders is the key.) The Ruby library was developed in 1993, 17 years before we figured out how to do type-safe operations without duplicating code. Also, Scala relies heavily on its complex static type system and type-level metaprogramming to find the correct collector at compile time. It is not necessary for the schema to work, but finding a constructor for each operation at runtime can be expensive.
What you can do is add new methods that are not part of the standard protocol Enumerable
, such as those similar to Scala mapValues
and mapKeys
.
source to share
AFAIK, this doesn't exist in Hash
out of the Ruby window, but here's a simple monkeypatch to achieve what you want:
▶ class Hash
▷ def hash_map &cb
▷ keys.zip(values.map(&cb)).to_h
▷ end
▷ end
There are more readable ways to achieve the requested functionality, but one uses inline values map
for values once, pretending to be the fastest implementation that comes to my mind.
▶ h = {a: 1, b: 2}
#⇒ { :a => 1, :b => 2 }
▶ h.hash_map do |v| v + 5 end
#⇒ { :a => 6, :b => 7 }
source to share