Converting hash keys to symbols

J

Jamis Buck

Golf question...

Is there an elegant way of converting all of the keys of a hash to a
symbol? The solution can assume that the existing keys are either
strings or symbols. Also, if a key is a string, it may contain a dash
character which must be converted to an underscore.

Something like this, only more elegant, would be nice:

a = some_hash_of_strings_and_symbols
new_a = Hash[*a.collect { |k,v|
k = k.gsub(/-/,"_").intern if k.is_a?(String)
[k,v] }.flatten]

Any takers?

- Jamis
 
M

Michael Neumann

Golf question...

Is there an elegant way of converting all of the keys of a hash to a
symbol? The solution can assume that the existing keys are either
strings or symbols. Also, if a key is a string, it may contain a dash
character which must be converted to an underscore.

Something like this, only more elegant, would be nice:

a = some_hash_of_strings_and_symbols
new_a = Hash[*a.collect { |k,v|
k = k.gsub(/-/,"_").intern if k.is_a?(String)
[k,v] }.flatten]

Any takers?

But you should not do this for random strings, as symbols are AFAIK not
GC'ed.

How about this (converts all symbols to strings, which is easier and
more secure, as strings get GC'ed):

h = Hash.new
a.each {|k,v| h[k.to_s.tr('-','_')] = v}
h

Regards,

Michael
 
J

James Britt

Jamis said:
Golf question...

Is there an elegant way of converting all of the keys of a hash to a
symbol? The solution can assume that the existing keys are either
strings or symbols. Also, if a key is a string, it may contain a dash
character which must be converted to an underscore.

Something like this, only more elegant, would be nice:

a = some_hash_of_strings_and_symbols
new_a = Hash[*a.collect { |k,v|
k = k.gsub(/-/,"_").intern if k.is_a?(String)
[k,v] }.flatten]

Any takers?

- Jamis

I'd be inclined to add 'intern' to Symbol, and just call intern on
everything in the key set. If you get a Symbol, then Symbol#intern just
returns self.

And override intern in String to do character subs.

James
 
J

Jamis Buck

Michael said:
But you should not do this for random strings, as symbols are AFAIK not
GC'ed.

Good point. I hadn't considered that. However, for what I'm doing, there
are no more than a double-handful of unique, valid strings and symbols,
so I don't think memory is an issue.
How about this (converts all symbols to strings, which is easier and
more secure, as strings get GC'ed):

h = Hash.new
a.each {|k,v| h[k.to_s.tr('-','_')] = v}
h

Ah, #tr is what I was looking for. Thanks! That's one step towards
making it more elegant, anyway.

Thanks, Michael!

- Jamis
 
J

Jamis Buck

James said:
I'd be inclined to add 'intern' to Symbol, and just call intern on
everything in the key set. If you get a Symbol, then Symbol#intern just
returns self.

And override intern in String to do character subs.

Good point. However, this is something that is only occurring at one
point in the code, and opening the classes to (re)define the methods is
a lot more lines of code than I'm up for at this point. :)

- (lazy) Jamis
 
F

Florian Gross

Jamis said:
Is there an elegant way of converting all of the keys of a hash to a
symbol? The solution can assume that the existing keys are either
strings or symbols.

Does this help?

a = Hash.new do |hash, key|
hash.fetch(key.is_a?(Symbol) ? key.to_s : key.to_sym, nil)
end

a["one"] = "eins"
a[:two] = "zwei"

a["one"] == a[:eek:ne] # => true
a["two"] == a[:two] # => true
Also, if a key is a string, it may contain a dash
character which must be converted to an underscore.

Why? Symbols can contain dash characters. See :"foo-bar", %s{foo-bar},
"foo-bar".intern and "foo-bar".to_sym.

Also note that #to_sym is defined for Symbol as well.

So maybe you could also do something like this (in case the above
doesn't work for you):

result = Hash.new(&a.default_proc)
until a.empty?
key, value = *a.shift
result[key.to_sym] = value
end
a.replace(result)
 
J

Jamis Buck

Florian said:
Does this help?

a = Hash.new do |hash, key|
hash.fetch(key.is_a?(Symbol) ? key.to_s : key.to_sym, nil)
end

Clever! That's really nice. It won't quite work for me, however, since I
don't have control over the creation of the hash that I'm receiving.
Why? Symbols can contain dash characters. See :"foo-bar", %s{foo-bar},
"foo-bar".intern and "foo-bar".to_sym.

Yah, I know. But I like to use symbols so I don't *have* to type the
quotes. :) It's a matter of convenience rather than optimization, in
this case.

Thanks for the suggestions, Florian. Thanks, especially, for pointing
out #to_sym. I wasn't aware of that, and I like it better than the
less-intuitive #intern.

- Jamis
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top