How to Swap Keys and Values in a Hash

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



Leave a reply



Submit