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.

+3


source to share


2 answers


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

.

+4


source


AFAIK, this doesn't exist in Hash

out of the Ruby window, but here's a simple monkeypatch to achieve what you want:

class Hashdef hash_map &cb
▷     keys.zip(values.map(&cb)).to_hendend

      



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 }

      

+3


source







All Articles