Reputation: 408
I'm trying to increment the key in a hash. For example. I'm trying to get this
{:b => "crayons", :c => "colors", :d => "apples"}
to turn into this
{:c => "crayons", :d => "colors", :e => "apples"}
I thought this code would do the trick but it doesn't. What do I need to change?
def hash(correct)
mapping = correct.each{|key, element| key.next}
Hash[correct.map {|key, element| [mapping[key], element]}]
end
Upvotes: 3
Views: 145
Reputation: 48599
I thought this code would do the trick but it doesn't.
mapping = correct.each{|key, element| key.next}
If you go to the ruby Symbol docs and click on the link for next()...surprise there is no entry for next, but the description at the top of the window says:
succ
Same as sym.to_s.succ.intern.
From that you have to deduce that next() is a synonym for succ(). So Symbol#next/succ converts the symbol to a string by calling to_s(). Well, you know that you are going to get a String returned from to_s, and no matter what you do to that String, e.g. calling String#succ on it, it isn't going to effect some Symbol, e.g. your hash key. Furthermore, if you look at the docs for String#succ, it says
succ -> new_string
...so String#succ creates another String object and calling intern() on that String object, and by the way intern() is just a synonym for to_sym(), once again won't affect some Symbol...and it won't even affect the String object returned by to_s.
Finally, intern() doesn't change the second string object but instead returns a Symbol:
a String
V
key.next => key.to_s.succ.intern => Symbol
^
another String
...and because you didn't do anything with the Symbol returned by intern(), it is discarded.
Upvotes: 1
Reputation: 110675
h = {:b => "crayons", :c => "colors", :d => "apples"}
h.keys.map(&:succ).zip(h.values).to_h
#=> {:c=>"crayons", :d=>"colors", :e=>"apples"}
If the intent were to modify (not keep) the original hash, the update could be done in place:
keys = h.keys.reverse
keys.each { |k| h[k.succ] = h[k] }
h.delete(keys.last)
which could be inscrutablized to:
h.delete(h.keys.reverse.each { |k| h[k.succ] = h[k] }.last)
Upvotes: 2
Reputation: 713
def hash(correct)
exp_hash = correct.map { | k, v| {k.next => v} }
Hash[*exp_hash.collect{|h| h.to_a}.flatten]
end
correct = {:b => "crayons", :c => "colors", :d => "apples"}
Upvotes: 1
Reputation: 9762
Using Enumerable#each_with_object
def hash_correct(hsh)
hsh.each_with_object({}) { |(k,v), hsh| hsh[k.succ] = v }
end
hash_correct({:b => "crayons", :c => "colors", :d => "apples"})
# => {:c=>"crayons", :d=>"colors", :e=>"apples"}
Upvotes: 5
Reputation: 168091
def hash(correct)
Hash[correct.map{|key, element| [key.next, element]}]
end
Upvotes: 4