How to change all the keys of a hash by a new set of given keys
Ruby 2.5 has Hash#transform_keys! method. Example using a map of keys
h = {a: 1, b: 2, c: 3}
key_map = {a: 'A', b: 'B', c: 'C'}
h.transform_keys! {|k| key_map[k]}
# => {"A"=>1, "B"=>2, "C"=>3}
You can also use symbol#toproc shortcut with transform_keys Eg:
h.transform_keys! &:upcase
# => {"A"=>1, "B"=>2, "C"=>3}
How to replace a hash key with another key
hash[:new_key] = hash.delete :old_key
How to make a particular change in all the keys of a hash?
You have to delete old keys from the hash and insert new ones,
use strict;
use warnings;
sub rename_keys {
my ($hash, $func) = @_;
my @k1 = my @k2 = keys %$hash;
$func->() for @k2;
@$hash{@k2} = delete @$hash{@k1};
}
my %hash = (
'IRQ_VSAFE_LPM_ASC_0' => '140',
'IRQ_VSAFE_LPM_ASC_1' => '141',
);
rename_keys(\%hash, sub { s/ASC_/ASC_1/ });
How to elegantly rename all keys in a hash in Ruby?
ages = { 'Bruce' => 32, 'Clark' => 28 }
mappings = { 'Bruce' => 'Bruce Wayne', 'Clark' => 'Clark Kent' }
ages.transform_keys(&mappings.method(:[]))
#=> { 'Bruce Wayne' => 32, 'Clark Kent' => 28 }
How to change all the dictionary keys in a for loop with d.items()?
It's never a good idea to change the object you're iterating over. Normally dict
even throws an exception when you attempt it:
name_dict = {1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6}
for k, v in name_dict.items():
name_dict.pop(k)
RuntimeError: dictionary changed size during iteration
However in your case you add one item for every removed item. That makes it more convolved. To understand what's happening you need to know that a dictionary is somewhat like a sparse table. For example a dictionary like {1: 1, 3: 3, 5: 5}
could look like this (this changed in Python 3.6, for 3.6 and newer the following isn't correct anymore):
hash key value
- - -
1 1 1
- - -
3 3 3
- - -
5 5 5
- - -
- - -
- - -
That's also the order in which it is iterated. So in the first iteration it will go to the second item (where the 1: 1
is stored). Let's assume you change the key to 2
and remove the key 1
the dict would look like this:
hash key value
- - -
- - -
2 2 1
3 3 3
- - -
5 5 5
- - -
- - -
- - -
But we're still at the second line, so the next iteration it will go to the next "not-empty" entry which is 2: 1
. Oups ...
It's even more complicated with strings as keys because string hashes are randomized (on a per session basis) so the order inside the dictionary is unpredictable.
In 3.6 the internal layout was changed a bit but something similar happens here.
Assuming you have this loop:
name_dict = {1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6}
for k, v in name_dict.items():
# print(k, k+6, name_dict.__sizeof__())
name_dict[k+6] = name_dict.pop(k)
# print(name_dict)
The initial layout is like this:
key value
1 1
2 2
3 3
4 4
5 5
6 1
The first loop removes 1
but adds 7
. Because dictionaries are ordered in 3.6 this inserts a placeholder where 1
had been:
key value
- -
2 2
3 3
4 4
5 5
6 1
7 2
This goes on until you replace 4
with 10
.
key value
- -
- -
- -
- -
5 5
6 1
7 2
8 3
9 4
10 5
But when you replace 5
with 11
the dictionary will need to increase it's size. Then something special happens: The placeholders are removed:
key value
6 6
7 1
8 2
9 3
10 4
11 5
So, we were at position 5 in the last iteration and now we change line 6. But line 6 contains 11: 5
right now. Oups...
Never change the object you're iterating over: Don't mess with the keys during iteration (values are okay)!
You could instead keep a "translation table" (don't know if that violates your "without creating a new dict" requirement but you need some kind of storage to make your code work correctly) and do the renaming after the loop:
translate = {}
for k, v in name_dict.items():
print("This is the key: '%s' and this is the value '%s'\n" % (k, v) )
new_key = input("Please enter a new key: ")
translate[k] = new_key
time.sleep(4)
for old, new in translate.items():
name_dict[new] = name_dict.pop(old)
How to change Hash values?
my_hash.each { |k, v| my_hash[k] = v.upcase }
or, if you'd prefer to do it non-destructively, and return a new hash instead of modifying my_hash
:
a_new_hash = my_hash.inject({}) { |h, (k, v)| h[k] = v.upcase; h }
This last version has the added benefit that you could transform the keys too.
How to change hash keys from `Symbol`s to `String`s?
simply call stringify_keys
(or stringify_keys!
)
http://apidock.com/rails/Hash/stringify_keys
How to remove a key from Hash and get the remaining hash in Ruby/Rails?
Rails has an except/except! method that returns the hash with those keys removed. If you're already using Rails, there's no sense in creating your own version of this.
class Hash
# Returns a hash that includes everything but the given keys.
# hash = { a: true, b: false, c: nil}
# hash.except(:c) # => { a: true, b: false}
# hash # => { a: true, b: false, c: nil}
#
# This is useful for limiting a set of parameters to everything but a few known toggles:
# @person.update(params[:person].except(:admin))
def except(*keys)
dup.except!(*keys)
end
# Replaces the hash without the given keys.
# hash = { a: true, b: false, c: nil}
# hash.except!(:c) # => { a: true, b: false}
# hash # => { a: true, b: false }
def except!(*keys)
keys.each { |key| delete(key) }
self
end
end
How to use the keys from a Hash to make a new Hash where each key's value is the key itself?
h = {'cat' => 'meow', 'dog' => nil}
#=> {"cat"=>"meow", "dog"=>nil}
Hash[h.keys.map{|k| [k,k]}]
#=> {"cat"=>"cat", "dog"=>"dog"}
Here's another, a bit dirty way (and I think it works in 1.8.6):
h.merge(h){|k,v,v| k}
Related Topics
Given an Array of Arguments, How to Send Those Arguments to a Particular Function in Ruby
How to Detect Certain Unicode Characters in a String in Ruby
Rails - Params with "Dot" (E.G. /Google.Com)
How to Convert a Ruby Hash to Xml
How to Check a Word Is Already All Uppercase
Uninstall Old Versions of Ruby Gems
Differencebetween Send_Data and Send_File in Ruby on Rails
How to Set Up Simple Http Authentication for a Ruby on Rails App on Heroku
Libxml2 Missing MAC Os X 10.10
Rails on Windows Is So Slow (Rails -V Takes 4 Seconds)
Using Instance Variables in Class Methods - Ruby
Ruby on Rails - Drop Down Box on Change Event
How to Simulate Java-Like Annotations in Ruby
Typing 'Rails Console' Doesn't Start
Can You Eval Code in the Context of a Caller in Ruby
Why Do People Say That Ruby Is Slow
"Which in Ruby": Checking If Program Exists in $Path from Ruby