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.

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

Gary Wright

···

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.

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 3, 12:12 pm, "Trans" <transf...@gmail.com> 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]

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 Feb 3, 2:17 pm, gwtm...@mac.com 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.

>
> > 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?

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".

···

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

On Feb 3, 2:17 pm, gwtm...@mac.com wrote:
> On Feb 3, 2007, at 12:12 PM, Trans wrote:
T.

Hi,

···

In message "Re: Hash#rekey" on Sun, 4 Feb 2007 04:49:08 +0900, "Trans" <transfire@gmail.com> 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.

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.

···

On Feb 4, 11:28 am, Yukihiro Matsumoto <m...@ruby-lang.org> wrote:

Hi,

In message "Re: Hash#rekey" > on Sun, 4 Feb 2007 04:49:08 +0900, "Trans" <transf...@gmail.com> 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.

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 Feb 3, 2007, at 12:46 PM, Logan Capaldo 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).

Hi,

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.

···

In message "Re: Hash#rekey" on Mon, 5 Feb 2007 03:08:15 +0900, "Trans" <transfire@gmail.com> writes:

Yeah I gathered as much from matz's replies

···

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

On Feb 3, 2007, at 12:46 PM, Logan Capaldo 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]

Yukihiro Matsumoto wrote:

>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

···

In message "Re: Hash#rekey" > on Mon, 5 Feb 2007 03:08:15 +0900, "Trans" <transfire@gmail.com> writes:

Hi,

>> 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.

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.

>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.

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

T.

···

On Feb 4, 1:37 pm, Yukihiro Matsumoto <m...@ruby-lang.org> wrote:

In message "Re: Hash#rekey" > on Mon, 5 Feb 2007 03:08:15 +0900, "Trans" <transf...@gmail.com> writes:

Yukihiro Matsumoto <matz@ruby-lang.org> writes:

Hi,

>> 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.

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

···

In message "Re: Hash#rekey" > on Mon, 5 Feb 2007 03:08:15 +0900, "Trans" <transfire@gmail.com> writes:

Hi,

···

In message "Re: Hash#rekey" on Mon, 5 Feb 2007 07:34:49 +0900, "Trans" <transfire@gmail.com> 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.

alter_key(s), perhaps

martin

···

On 2/6/07, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

Hi,

In message "Re: Hash#rekey" > on Mon, 5 Feb 2007 07:34:49 +0900, "Trans" <transfire@gmail.com> 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 Feb 6, 2:35 am, Yukihiro Matsumoto <m...@ruby-lang.org> wrote:

Hi,

In message "Re: Hash#rekey" > on Mon, 5 Feb 2007 07:34:49 +0900, "Trans" <transf...@gmail.com> 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.

# 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

···

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

On 2/6/07, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:
>Hi,
>
>In message "Re: Hash#rekey" > > on Mon, 5 Feb 2007 07:34:49 +0900, "Trans" <transfire@gmail.com> > > 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

Hi,

···

In message "Re: Hash#rekey" on Tue, 6 Feb 2007 22:09:31 +0900, "Trans" <transfire@gmail.com> 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.

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

···

On Wednesday 07 February 2007 07:34, Yukihiro Matsumoto wrote:

    on Tue, 6 Feb 2007 22:09:31 +0900, "Trans" <transfire@gmail.com> 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.

--
pub 1024D/8D2787EF 723C 7CA3 3C19 2ACE 6E20 9CC1 9956 EB3C 8D27 87EF