Hash#rekey

There are a few facets (ie. extensions) I find myself using often. One
of these is Hash#rekey. I used to use other methods like those found
in the Gavin’s Extensions project and DHH’s ActiveSupport, eg.
#convert_keys, #symbolize_keys, #stringify_keys, and so on. But ever
since I came up with #rekey, it’s been clear that it’s more
advantageous and replaces all of these other methods and then some.

I think it would be a good candidate for Ruby proper – even 1.8
series. Though it will undoubtedly be less useful in Ruby 2.0 when
string and symbol hash keys key for the same entry, it is still useful
in other ways. Here it is my implementation… note that
Symbol#to_proc is used.

require ‘facets/core/symbol/to_proc’

class Hash

# Converts all keys in the Hash accroding to the given block.
# If the block return +nil+ for given key, then that key will be
# left intact.
#
#   foo = { :name=>'Tom', :friend=>:Gavin }
#   foo.rekey{ |k| k.to_s }  #=>  { "name"=>"Tom",

“friend”=>:Gavin }
# foo.inspect #=> { :name
=>“Tom”, :friend=>:Gavin }

def rekey( meth=nil, &block )
  raise ArgumentError, "2 for 1" if meth and block
  dup.send(:rekey!, meth, &block)
end

# Synonym for Hash#rekey, but modifies the receiver in place (and

returns it).
#
# foo = { :name=>‘Tom’, :friend=>:Gavin }
# foo.rekey!{ |k| k.to_s } #=> { “name”=>“Tom”,
“friend”=>:Gavin }
# foo.inspect #=> { “name”=>“Tom”,
“friend”=>:Gavin }

def rekey!( meth=nil, &block )
  meth = :to_sym unless meth or block
  raise ArgumentError, "2 for 1" if meth and block
  block = meth.to_sym.to_proc if meth
  keys.each do |k|
    nk = block[k]
    self[nk]=delete(k) if nk
  end
  self
end

end

Improvements to implementation welcome… no… encouraged, of course.

T.

On Feb 3, 2007, at 12:12 PM, Trans wrote:

Though it will undoubtedly be less useful in Ruby 2.0 when
string and symbol hash keys key for the same entry, it is still useful
in other ways.

I seem to remember that matz backed off from this idea.

Gary W.

On Feb 3, 2:17 pm, [email protected] wrote:

On Feb 3, 2007, at 12:12 PM, Trans wrote:

Though it will undoubtedly be less useful in Ruby 2.0 when
string and symbol hash keys key for the same entry, it is still useful
in other ways.

I seem to remember that matz backed off from this idea.

I think he backed off making Symbol a subclass of String, but I think
he’s still considering auto-coercing symbol to string, or at the very
least that they will have some sort of equality for use as hash keys.
Matz?

T.

On Sun, Feb 04, 2007 at 04:49:08AM +0900, Trans wrote:

I think he backed off making Symbol a subclass of String, but I think
he’s still considering auto-coercing symbol to string, or at the very
least that they will have some sort of equality for use as hash keys.
Matz?

Incidently, I’d like to point out why I think that’s an especially bad
idea (only equivalent in hashes)
[“foo”, :foo, 2].uniq #=> [“foo”, 2]
[1, 1.0, 2].uniq #=> [1, 1.0, 2]
But; 1 == 1.0 and :foo != “foo” (at least if the equality only applies
in hashes, in #hash and #eql? IOW).

I find it very “warty”.

Hi,

In message “Re: Hash#rekey”
on Sun, 4 Feb 2007 04:49:08 +0900, “Trans” [email protected]
writes:

|I think he backed off making Symbol a subclass of String, but I think
|he’s still considering auto-coercing symbol to string, or at the very
|least that they will have some sort of equality for use as hash keys.
|Matz?

No. “foo” and :foo are different keys in a hash.

          matz.

On Feb 3, 12:12 pm, “Trans” [email protected] wrote:

I think it would be a good candidate for Ruby proper – even 1.8
series. Though it will undoubtedly be less useful in Ruby 2.0 when
string and symbol hash keys key for the same entry, it is still useful
in other ways. Here it is my implementation… note that
Symbol#to_proc is used.

[snip]

Sheesh I forgot the most basic examples!

{ “a”=>1, :b=>2}.rekey #=> { :a=>1, :b=>2}
{ “a”=>1, :b=>2}.rekey(:to_s) #=> { “a”=>1, “b”=>2}

T.

On Feb 4, 11:28 am, Yukihiro M. [email protected] wrote:

No. “foo” and :foo are different keys in a hash.
And never the twain shall meet? So it’s long live
HashWithIndifferentAccess ?

A while back I offered the idea of being able to define a key coerce
proc, eg.

h = Hash.new.key!{ |k| k.to_s }

Such that keys would always be strings. Might someting like that be a
viable solution?

In anycase, I still offer up #rekey.

T.

Yukihiro M. wrote:

In message “Re: Hash#rekey”
on Mon, 5 Feb 2007 03:08:15 +0900, “Trans” [email protected] writes:
|A while back I offered the idea of being able to define a key coerce
|proc, eg.
|
| h = Hash.new.key!{ |k| k.to_s }
|
|Such that keys would always be strings. Might someting like that be a
|viable solution?
I quite like this idea.

Maybe, but not with a name like “key!”.
key_coerce? coerce_key? key_proc=?

I don’t think “rekey” represents the behavior well. Any better name?
transpose_keys comes to my mind.
Well, given what it’s doing, map_key! seems logical – map! + each_key.
('course, logical != intuitive…)

Devin

Hi,

In message “Re: Hash#rekey”
on Mon, 5 Feb 2007 03:08:15 +0900, “Trans” [email protected]
writes:

|> No. “foo” and :foo are different keys in a hash.
|
|And never the twain shall meet? So it’s long live
|HashWithIndifferentAccess ?

The HashWithIndifferentAccess behavior will not be default even after
Ruby 2.0; that’s for sure.

|A while back I offered the idea of being able to define a key coerce
|proc, eg.
|
| h = Hash.new.key!{ |k| k.to_s }
|
|Such that keys would always be strings. Might someting like that be a
|viable solution?

Maybe, but not with a name like “key!”.

|In anycase, I still offer up #rekey.

I don’t think “rekey” represents the behavior well. Any better name?
transpose_keys comes to my mind.

          matz.

On Feb 3, 2007, at 12:46 PM, Logan C. wrote:

Incidently, I’d like to point out why I think that’s an especially bad
idea (only equivalent in hashes)
[“foo”, :foo, 2].uniq #=> [“foo”, 2]
[1, 1.0, 2].uniq #=> [1, 1.0, 2]
But; 1 == 1.0 and :foo != “foo” (at least if the equality only
applies
in hashes, in #hash and #eql? IOW).

Not anymore:

% ./ruby-19 -v -e ‘p [“foo”, :foo, 2].uniq’
ruby 1.9.0 (2007-02-05 patchlevel 0) [i686-darwin8.8.1]
[“foo”, :foo, 2]

On Mon, Feb 05, 2007 at 06:25:08PM +0900, Ryan D. wrote:

Not anymore:

% ./ruby-19 -v -e ‘p [“foo”, :foo, 2].uniq’
ruby 1.9.0 (2007-02-05 patchlevel 0) [i686-darwin8.8.1]
[“foo”, :foo, 2]

Yeah I gathered as much from matz’s replies

On Feb 4, 1:37 pm, Yukihiro M. [email protected] wrote:

The HashWithIndifferentAccess behavior will not be default even after
Ruby 2.0; that’s for sure.

Okay, well I though the whole reason you considerd making Symbols a
subclass of String was basically to remove the need for this sort of
thing. Honestly, keyword lists are increasing common as prameter args
and I for get tired of putting

opts = opts.stringify_keys

at the beginning of every such method. not to mention normalizing keys
when the are stored in such hash.

|In anycase, I still offer up #rekey.

I don’t think “rekey” represents the behavior well. Any better name?
transpose_keys comes to my mind.

I used ‘normalize_keys’ for while, but how doesn’t ‘rekey’ fit the
behavior? The hash is being rekey’d.

T.

On 2/6/07, Yukihiro M. [email protected] wrote:

Hi,

In message “Re: Hash#rekey”
on Mon, 5 Feb 2007 07:34:49 +0900, “Trans” [email protected] writes:

|I used ‘normalize_keys’ for while, but how doesn’t ‘rekey’ fit the
|behavior? The hash is being rekey’d.

For me, ‘rekey’ is meaningless. Coined word need guessing, which is
considered harmful unless it is accepted by many.

alter_key(s), perhaps

martin

On Tue, Feb 06, 2007 at 09:34:02PM +0900, Martin DeMello wrote:

For me, ‘rekey’ is meaningless. Coined word need guessing, which is
considered harmful unless it is accepted by many.

alter_key(s), perhaps

existing

a = [:one, :two, :three]
a.map! { |k| k.to_s }
puts a.inspect

by analogy

h = [:one=>1, :two=>2, :three=>3]
h.map_keys! { |k| k.to_s }
puts h.inspect

Hi,

In message “Re: Hash#rekey”
on Mon, 5 Feb 2007 07:34:49 +0900, “Trans” [email protected]
writes:

|I used ‘normalize_keys’ for while, but how doesn’t ‘rekey’ fit the
|behavior? The hash is being rekey’d.

For me, ‘rekey’ is meaningless. Coined word need guessing, which is
considered harmful unless it is accepted by many.

          matz.

Hi,

In message “Re: Hash#rekey”
on Tue, 6 Feb 2007 22:09:31 +0900, “Trans” [email protected]
writes:

|> For me, ‘rekey’ is meaningless. Coined word need guessing, which is
|> considered harmful unless it is accepted by many.
|
|The use of re- as a prefix is very normal in English.

Of course I know the prefix pre-, but it is difficult (for me at
least) to guess what verb ‘key’ means here. That’s my point.

          matz.

On Feb 6, 2:35 am, Yukihiro M. [email protected] wrote:

Hi,

In message “Re: Hash#rekey”
on Mon, 5 Feb 2007 07:34:49 +0900, “Trans” [email protected] writes:

|I used ‘normalize_keys’ for while, but how doesn’t ‘rekey’ fit the
|behavior? The hash is being rekey’d.

For me, ‘rekey’ is meaningless. Coined word need guessing, which is
considered harmful unless it is accepted by many.

The use of re- as a prefix is very normal in English. Consider Merriam-
Webster’s list

Re- Definition & Meaning - Merriam-Webster

I certainly didn’t coin the word. Common connotations include: re-
entering data via keyboard as well as altering a combination of a
lock. So, for altering the keys of a hash it makes prefect sense.

Anyway I won’t go on about it any longer. Personally I’m just not
found of having to type longer winded method name.

T.

On Wednesday 07 February 2007 07:34, Yukihiro M. wrote:

on Tue, 6 Feb 2007 22:09:31 +0900, "Trans" <[email protected]> writes:

|> For me, ‘rekey’ is meaningless. Coined word need guessing, which is
|> considered harmful unless it is accepted by many.
|
|The use of re- as a prefix is very normal in English.

Of course I know the prefix pre-, but it is difficult (for me at
least) to guess what verb ‘key’ means here. That’s my point.

what about reindex ? hash is a dictionary, and the method… reindexes it
:slight_smile:

Yukihiro M. [email protected] writes:

The HashWithIndifferentAccess behavior will not be default even after
Maybe, but not with a name like “key!”.

|In anycase, I still offer up #rekey.

I don’t think “rekey” represents the behavior well. Any better name?
transpose_keys comes to my mind.

          matz.

How about this?

hsh.map! {|h,k,v| h[k.to_s] = v}

Or maybe a block argument to #rehash?

h.rehash {|h,k,v| h[k.to_s] = v}

Instead of key!, #coerce_key_proc.

FYI, the word “rekey” has at least two common usages in (American?)
English.

  1. to transcribe a text again, using a keyboard
    “Due to poor image quality, the OCR output for those documents
    is unusable and we will have to rekey them.”

  2. to reconfigure a lock so that it can be opened by a different
    key, and usually not be opened by the original key
    “We hired a locksmith to rekey all of the doors in our new house.”

Both are technically jargon, although (2) is pretty universal. Both
are more common than “key” as a verb, I think.

I prefer Hash#map! or a block argument to #rehash. It’s more general
without being more expensive.

Steve