How to swap keys and values in a hash
Ruby has a helper method for Hash that lets you treat a Hash as if it was inverted (in essence, by letting you access keys through values):
{a: 1, b: 2, c: 3}.key(1)
=> :a
If you want to keep the inverted hash, then Hash#invert should work for most situations:
{a: 1, b: 2, c: 3}.invert
=> {1=>:a, 2=>:b, 3=>:c}
BUT...
If you have duplicate values, invert
will discard all but the last occurrence of your values (because it will keep replacing new value for that key during iteration). Likewise, key
will only return the first match:
{a: 1, b: 2, c: 2}.key(2)
=> :b
{a: 1, b: 2, c: 2}.invert
=> {1=>:a, 2=>:c}
So, if your values are unique you can use Hash#invert
. If not, then you can keep all the values as an array, like this:
class Hash
# like invert but not lossy
# {"one"=>1,"two"=>2, "1"=>1, "2"=>2}.inverse => {1=>["one", "1"], 2=>["two", "2"]}
def safe_invert
each_with_object({}) do |(key,value),out|
out[value] ||= []
out[value] << key
end
end
end
Note: This code with tests is now on GitHub.
Or:
class Hash
def safe_invert
self.each_with_object({}){|(k,v),o|(o[v]||=[])<<k}
end
end
Swap hash keys with values and convert keys to symbols in Ruby?
You can do this:
Hash[periods.values.zip(periods.keys.map(&:to_sym))]
Or if you're using a version of Ruby where to_h
is available for arrays, you can do this:
periods.values.zip(periods.keys.map(&:to_sym)).to_h
What the two examples above do is make arrays of the keys and values of the original hash. Note that the string keys of the hash are mapped to symbols by passing to_sym
to map
as a Proc
:
periods.keys.map(&:to_sym)
# => [:q1, :q2, :q3, :q4, :h1, :h2]
periods.values
# => [0, 1, 2, 3, 4, 5]
Then it zips them up into an array of [value, key]
pairs, where each corresponding elements of values
is matched with its corresponding key in keys
:
periods.values.zip(periods.keys.map(&:to_sym))
# => [[0, :q1], [1, :q2], [2, :q3], [3, :q4], [4, :h1], [5, :h2]]
Then that array can be converted back into a hash using Hash[array]
or array.to_h
.
Swap keys in ruby hash
The simplest way would be:
h = {:one => 1, :two => 2, :three => 3, :four => 4}
h[:two], h[:three] = h[:three], h[:two]
If this is something you need to do regularly, you can define a method on Hash that allows for a prettier syntax:
class Hash
def swap!(a, b)
self[a], self[b] = self[b], self[a] if key?(a) && key?(b)
self
end
def swap(a, b)
self.dup.swap!(a, b)
end
end
Note, however, that both of these solutions will preserve the order of key-value pairs in the hash. If you want to actually swap the keys as well as their values, you can do this:
class Hash
def swap(a, b)
self.inject(Hash.new) do |h, (k,v)|
if k == a
h[b] = self[a]
elsif k == b
h[a] = self[b]
else
h[k] = v
end
h
end
end
end
{:one => 1, :two => 2, :three => 3, :four => 4}.swap(:two, :three)
# results in {:one=>1, :three=>2, :two=>3, :four=>4}
Though I'm not sure why you'd want to do that.
Swap keys with values and vice versa of HashMap
You'll need a new Map
, since the keys and values in your example have different types.
In Java 8 this can be done quite easily by creating a Stream
of the entries of the original Map
and using a toMap
Collector
to generate the new Map
:
Map<String,Integer> newMap =
s.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getValue,Map.Entry::getKey));
How to swap keys and values in a Map elegantly
The standard API / Java runtime doesn't offer a bi-directional map, so the only solution is to iterate over all entries and swap them manually.
What you can do is create a wrapper class which contains two maps and which does a dual put()
internally so you have fast two views on the data.
[EDIT] Also, thanks to open source, you don't have to include a third party library, you can simply copy the classes you need into your own project.
How do I exchange keys with values in a dictionary?
Python 2:
res = dict((v,k) for k,v in a.iteritems())
Python 3 (thanks to @erik):
res = dict((v,k) for k,v in a.items())
Swap key with value in object
function swap(json){
var ret = {};
for(var key in json){
ret[json[key]] = key;
}
return ret;
}
Example here FIDDLE don't forget to turn on your console to see the results.
ES6 versions:
static objectFlip(obj) {
const ret = {};
Object.keys(obj).forEach(key => {
ret[obj[key]] = key;
});
return ret;
}
Or using Array.reduce() & Object.keys()
static objectFlip(obj) {
return Object.keys(obj).reduce((ret, key) => {
ret[obj[key]] = key;
return ret;
}, {});
}
Or using Array.reduce() & Object.entries()
static objectFlip(obj) {
return Object.entries(obj).reduce((ret, entry) => {
const [ key, value ] = entry;
ret[ value ] = key;
return ret;
}, {});
}
Inverting a Hash's Key and Values in Perl
Adapted from http://www.dreamincode.net/forums/topic/46400-swap-hash-values/:
Assuming your hash is stored in $hash
:
while (($key, $value) = each %hash) {
$hash2{$value}=$key;
}
%hash=%hash2;
Seems like much more elegant solution can be achieved with reverse (http://www.misc-perl-info.com/perl-hashes.html#reverseph):
%nhash = reverse %hash;
Note that with reverse, duplicate values will be overwritten.
Related Topics
To Use Self. or Not.. in Rails
Ruby/Rails - Change the Timezone of a Time, Without Changing the Value
Undefined Method 'Visit' When Using Rspec and Capybara in Rails
Difference Between $Stdout and Stdout in Ruby
How to Implement a Short Url Like the Urls in Twitter
Execute Bash Commands from a Rakefile
Unzip (Zip, Tar, Tag.Gz) Files With Ruby
In Rails, How to Add a New Method to String Class
Ruby 1.9.2 How to Install Rmagick on Windows
Include Jekyll/Liquid Template Data in a Yaml Variable
Merge and Interleave Two Arrays in Ruby
Ruby - Access Multidimensional Hash and Avoid Access Nil Object
Uninstalling All Gems Ruby 2.0.0
Correctly Doing Redirect_To :Back in Ruby on Rails When Referrer Is Not Available
Ruby on Rails - Unable to Convert "\X89" from Ascii-8Bit to Utf-8 for Xxx/Xxxx/Xxxx