4
\$\begingroup\$

Input

A dictionary with string keys and string values.

Output

The 'inversedict' of this dictionary.

How to make an inversedict

An inversedict is a dictionary with string keys and string array values. The keys are the values from the original dictionary, and the values are the keys from the original dictionary with that value from the original dictionary.

An example

Input
["Clyde": "blue", "Sarah": "blue", "Fred": "green"]
Output
["blue": ["Clyde", "Sarah"], "green": ["Fred"]]

This is , so shortest code in bytes wins!

\$\endgroup\$
  • 1
    \$\begingroup\$ Does our language need to have dictionaries? Can we use a list of tuples? \$\endgroup\$ – xnor Nov 18 '16 at 4:14
  • 1
    \$\begingroup\$ @xnor, that's allowed if your language does not have dictionaries \$\endgroup\$ – Daniel Nov 18 '16 at 4:14
  • \$\begingroup\$ Wait, isn't a defaultdict a dictionary that defaults to some value or function on a missing key? This looks like an "inverse" of a dictionary. \$\endgroup\$ – xnor Nov 18 '16 at 4:16
  • \$\begingroup\$ @xnor, yeah that makes a lot more sense :) \$\endgroup\$ – Daniel Nov 18 '16 at 4:17
  • 3
    \$\begingroup\$ Haskell calls this flipAL with AL for association list (from Data.Lists). You might want to ban built-ins that do this. \$\endgroup\$ – xnor Nov 18 '16 at 4:25

16 Answers 16

4
\$\begingroup\$

Mathematica, 28 bytes

Merge[Reverse/@Normal@#,#&]&

The input is an Association, the output is an Association too.

Explanation

Normal@#

Convert the input Association to a List of Rules.

Reverse/@ ...

Reverse the Rules.

Merge[ ... ,#&]

Merge all Rules, grouping duplicates with a List and then with the identity operation. Creates an Association.

Usage

Merge[Reverse/@Normal@#,#&]&[
 <|"Clyde" -> "blue", "Sarah" -> "blue", "Fred" -> "green"|>
]

<|"blue" -> {"Clyde", "Sarah"}, "green" -> {"Fred"}|>

\$\endgroup\$
4
\$\begingroup\$

Python 2, 54 bytes

lambda i:{i[k]:[a for a in i if i[a]==i[k]]for k in i}

Usage:

f=lambda i:{i[k]:[a for a in i if i[a]==i[k]]for k in i}
print f({"Clyde": "blue", "Sarah": "blue", "Fred": "green"})

Gives

{'blue': ['Sarah', 'Clyde'], 'green': ['Fred']}
\$\endgroup\$
3
\$\begingroup\$

Brachylog, 10 bytes

tᵍ⟨ttʰhᵐ⟩ᵐ

Try it online!

Takes input as a list of [key, value] pairs through the input variable, and outputs a list of [value, [keys]] pairs through the output variable.

 ᵍ            Group the elements of
              the input
t             by their last elements.
         ᵐ    For each group,
   t          its last element
  ⟨     ⟩     paired with
      hᵐ      the first element of every element
     ʰ        with the first element of the pair being replaced by
    t         its last element
         ᵐ    is the corresponding element of
              the output.

...such an eloquent explanation...

\$\endgroup\$
2
\$\begingroup\$

Rust, 127 bytes

use std::collections::HashMap as H;|m:H<String,String>|{let mut n=H::new();for(k,v)in m{n.entry(v).or_insert(vec![]).push(k)}n}

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Pyth, 10 bytes

uXeHG]hHQH

Try it online!

uXeHG]hHQH   Implicit: Q=eval(input()), H={} (empty dictionary)
u       Q    Reduce elements of Q...
         H   ... starting with an empty dictionary...
             ... current value is G, next value is H:
 X  G          Add to G...
  eH           ... with key as last element of H (i.e. value from original input dictionary)...
     ]hH       ... value as first element of H, wrapped in a list
               This adds a new single-element list if the key is not alrady present, or concatenates values if it is
\$\endgroup\$
1
\$\begingroup\$

Lua, 82 Bytes

function(t)g={}for k,v in pairs(t)do g[v]=g[v]or{}g[v][#g[v]+1]=k end return g end

An anonymous function which takes a table as an input and outputs the inverse dict.

Commented and Ungolfed.

function(t)                     #Anonymous Function.
    g={}                        #Define the output array.
    for k,v in pairs(t) do      #For each value in the input by key value pairs.
        g[v]= g[v] or {}        #Set the value of the output dictionary with the key v, to either itself, or a new table if it's null.
        g[v] [#g[v]+1] = k      #Set a new value (#g[v]+1 is the key that is +1 the count, lua is 1 indexed) to the key.
    end                         #This loop will append values with the same 'key', instead of set. However, makes all output in table form.
    return g                    #Output g
end                             #End
\$\endgroup\$
1
\$\begingroup\$

JavaScript (ES6), 57 bytes

d=>eval("r={};for(i in d)(r[j=d[i]]=r[j]||[]).push(i);r")

Input and output are as Objects, e.g. {"Clyde": "blue", "Sarah": "blue", "Fred": "green"}

\$\endgroup\$
  • \$\begingroup\$ Just wondering since I don't know much about JS, why do you need to put this in an eval()? \$\endgroup\$ – Kade Nov 18 '16 at 14:31
  • \$\begingroup\$ @Shebang You don't have to, but d=>{r={};for(i in d)(r[j=d[i]]=r[j]||[]).push(i);return r} is one byte longer because of the return. \$\endgroup\$ – ETHproductions Nov 18 '16 at 14:37
  • \$\begingroup\$ Ah, that explains it :) Nice answer! \$\endgroup\$ – Kade Nov 18 '16 at 14:50
1
\$\begingroup\$

C#6, 136 bytes

using System.Collections.Generic;using System.Linq;ILookup<string,string>F(Dictionary<string,string>d)=>d.ToLookup(x=>x.Value,x=>x.Key);

repl.it demo

Seriously, do I really need to ungolf this? Just create an ILookup with input value as output key and input key as output value.

\$\endgroup\$
1
\$\begingroup\$

C++17, 158 bytes

#import<string>
#import<map>
#import<vector>
[](auto m){std::map<std::string,std::vector<std::string>>n;for(auto x:m)n[x.second].push_back(x.first);return n;}

Ungolfed and usage:

#include<iostream>
#include<string>
#include<map>
#include<vector>

auto f=
[](auto m){
 std::map<std::string,std::vector<std::string>>n;  //using namespace is equally long
 for(auto x:m)
  n[x.second].push_back(x.first);
 return n;
}
;

using namespace std;

int main(){
 map<string,string> m={
  {"a","x"},{"b","x"},{"c","y"}
 };
 auto n = f(m);
 for (auto x:n){
  cout << x.first << ": ";
  for (auto y:x.second)
   cout << y << ", ";
  cout << "\n";
 }
 cout << "\n";
}
\$\endgroup\$
1
\$\begingroup\$

Japt, 9 bytes

Input is as a 2D-array: [[key,value],[key,value],...].
Output is as a 3D-array: [[value,[key,key,...]],[value,[key,key,...]],...].

üÌ®ÎÅpZmÎ

Try it

üÌ®ÎÅpZmÎ     :Implicit input of array        [["Clyde","blue"],["Sarah","blue"],["Fred","green"]]
ü             :Group and sort by
 Ì            :  Last element of each         [[["Clyde","blue"],["Sarah","blue"]],[["Fred","green"]]]
  ®           :Map each Z
   Î          :  First element of Z           [["Clyde","blue"],["Fred","green"]]
    Å         :  Slice off the first element  [["blue"],["green"]]
     p        :  Push
      Zm      :    Map Z
        Î     :      First element            [["blue",["Clyde","Sarah"]],["green",["Fred"]]]

If output must be a 2D-array then:

10 bytes

üÌc_ÎÅpZmÎ

Try it

The _, essentially, serves the same purpose as the ® above and the c flattens the array by one level afterwards.

\$\endgroup\$
0
\$\begingroup\$

Perl, 36 bytes

This is an anonymous function which takes a hash (not hash reference) as an argument, and returns a hash (not a hash reference) as its result. (A "hash" is Perl's name for a dictionary.) Although the language has dictionaries, it doesn't have sets; thus, for the values of the inverse dictionary (which are logically sets), I used the common Perl representation of a set as a hash, in which the keys are the set elements and the values are irrelevant.

Here's the program itself:

sub{my%t;$t{+pop}{+pop}++while@_;%t}

Here's how I tested it:

use Data::Dumper;
$f = sub{my%t;$t{+pop}{+pop}++while@_;%t};
my %test = qw/sky blue sea blue grass green/;
print Dumper({&$f(%test)});

The dump of the resulting hash is:

$VAR1 = {
          'blue' => {
                      'sky' => 1,
                      'sea' => 1
                    },
          'green' => {
                       'grass' => 1
                     }
        };

which is the expected value.

\$\endgroup\$
0
\$\begingroup\$

Haskell, 55 bytes

foldl(\l(k,v)->maybe(v,[k])((,)v.(k:))(lookup v l):l)[]

This uses the good old association list as the data structure, which means that the output list may contain multiple elements with the same key, where only the first one is valid. However, I exploit the fact that the keys in the input list are all distinct.

Usage example:

*Main> foldl(\l(k,v)->maybe(v,[k])((,)v.(k:))(lookup v l):l)[] [("Clyde","blue"),("Sarah","blue"),("Fred","green")]
[("green",["Fred"]),("blue",["Sarah","Clyde"]),("blue",["Clyde"])]

How it works:

foldl(   )[]                    -- starting with the empty list, reduce the
                                -- input list
    \l (k,v)->                  -- with via a lambda function that takes a list l
                                -- (the output list so far) and a key-value-pair
                                -- (k,v) from the input list and returns the next
                                -- version of the output list, which is made by:
                          :l    -- prepend to the existing list 
      maybe   (lookup v l)      -- if v is already a key in the output
           (,)v.(k:)            --     prepend k to the list for v
                                --     (this leaves the current pair in places and
                                --     adds the updated version to the front)
         (v,[k])                -- else a new pair with v and k flipped
                                --     and k put into a singleton list
\$\endgroup\$
0
\$\begingroup\$

Racket 208 bytes

(let p((l2(remove-duplicates(map(λ(x)(list-ref x 1))ll)))(ol'()))(cond[(empty? l2)(reverse ol)][ 
(p(rest l2)(cons(cons(first l2)(for/list((i ll)#:when(equal?(first l2)(list-ref i 1)))(list-ref i 0)))ol))]))

Ungolfed:

(define (f ll)
  (define l2 (remove-duplicates (map (λ (x) (list-ref x 1)) ll)))     
  (let loop ((l2 l2)
             (ol '()))
    (cond
      [(empty? l2) (reverse ol)]
      [else 
       (define tl (for/list ((i ll) #:when (equal? (first l2) (list-ref i 1)))
                    (list-ref i 0)))
       (loop (rest l2) (cons (cons (first l2) tl) ol))
       ])))

Testing:

(f '[("Clyde" "blue") ("Sarah" "blue") ("Fred" "green")])

Output:

'(("blue" "Clyde" "Sarah") ("green" "Fred"))
\$\endgroup\$
0
\$\begingroup\$

Groovy, 56 53 bytes

{m=[:];it.each{k,v->if(!m."$v"){x=m."$v"=[]};x<<k};m}

Testing

({m=[:];it.each{k,v->if(!m."$v"){x=m."$v"=[]};x<<k};m})(["Clyde": "blue", "Sarah": "blue", "Fred": "green"])

Output

[blue:[Clyde, Sarah], green:[Fred]]
\$\endgroup\$
0
\$\begingroup\$

Java 7, 211 205 bytes

golfed:

Map<String,List<String>>i(Map<String,String>m){Map<String,List<String>>r=new HashMap<>();for(String k:m.keySet()){String s=m.get(k);if(r.get(s)==null)r.put(s, new ArrayList<>());r.get(s).add(k);}return r;}

ungolfed:

public static Map<String, List<String>> i(Map<String, String> m)
{
    Map<String, List<String>> r = new HashMap<>();
    for (String k : m.keySet())
    {
        String s = m.get(k);
        if (r.get(s) == null)
            r.put(s, new ArrayList<>());
        r.get(s).add(k);
    }
    return r;
}

Test it online!

Java ... the worst golfing language.

\$\endgroup\$
0
\$\begingroup\$

R, 79 69 bytes

function(l)setNames(lapply(u,function(x)names(l)[l==x]),u<-unique(l))

R does not have a dictionary by default but the closest approximation to a dictionary is an object of class list. It's basically a generic vector allowing for multiple data types where each value (can basically be any R-object) is allowed to have a name/key.

Example

A list with keys/names can be created as e.g.:

l <- list(Clyde="blue", Sarah="blue", Fred="green")

Which if printed returns:

$Clyde
[1] "blue"

$Sarah
[1] "blue"

$Fred
[1] "green"

Calling the function now returns:

$blue
[1] "Clyde" "Sarah"

$green
[1] "Fred"
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.