Return a set of pairs of keys from a dictionary that have a common value











up vote
2
down vote

favorite












How can I write a function, that would take a dictionary and return me a set that would consist of pairs of keys that have at least one common value?



Example:



I have the following dictionary:



dict = {
'C': {'123'},
'A': {'123', '456'},
'D': {'123'},
'B': {'789', '456'},
'E': {'789'}}


MyFunction(dict) should return me:



{("A", "B"), ("A", "C"), ("A", "D"), ("B", "E"), ("C", "D")}









share|improve this question
























  • Side note: never (even as an example) shadow built-ins, e.g. use d or dct or dict_ instead of dict.
    – jpp
    Nov 21 at 21:49















up vote
2
down vote

favorite












How can I write a function, that would take a dictionary and return me a set that would consist of pairs of keys that have at least one common value?



Example:



I have the following dictionary:



dict = {
'C': {'123'},
'A': {'123', '456'},
'D': {'123'},
'B': {'789', '456'},
'E': {'789'}}


MyFunction(dict) should return me:



{("A", "B"), ("A", "C"), ("A", "D"), ("B", "E"), ("C", "D")}









share|improve this question
























  • Side note: never (even as an example) shadow built-ins, e.g. use d or dct or dict_ instead of dict.
    – jpp
    Nov 21 at 21:49













up vote
2
down vote

favorite









up vote
2
down vote

favorite











How can I write a function, that would take a dictionary and return me a set that would consist of pairs of keys that have at least one common value?



Example:



I have the following dictionary:



dict = {
'C': {'123'},
'A': {'123', '456'},
'D': {'123'},
'B': {'789', '456'},
'E': {'789'}}


MyFunction(dict) should return me:



{("A", "B"), ("A", "C"), ("A", "D"), ("B", "E"), ("C", "D")}









share|improve this question















How can I write a function, that would take a dictionary and return me a set that would consist of pairs of keys that have at least one common value?



Example:



I have the following dictionary:



dict = {
'C': {'123'},
'A': {'123', '456'},
'D': {'123'},
'B': {'789', '456'},
'E': {'789'}}


MyFunction(dict) should return me:



{("A", "B"), ("A", "C"), ("A", "D"), ("B", "E"), ("C", "D")}






python python-3.x function dictionary set






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 21 at 21:40









jpp

86.2k194898




86.2k194898










asked Nov 21 at 21:30









Tadej Firšt

155




155












  • Side note: never (even as an example) shadow built-ins, e.g. use d or dct or dict_ instead of dict.
    – jpp
    Nov 21 at 21:49


















  • Side note: never (even as an example) shadow built-ins, e.g. use d or dct or dict_ instead of dict.
    – jpp
    Nov 21 at 21:49
















Side note: never (even as an example) shadow built-ins, e.g. use d or dct or dict_ instead of dict.
– jpp
Nov 21 at 21:49




Side note: never (even as an example) shadow built-ins, e.g. use d or dct or dict_ instead of dict.
– jpp
Nov 21 at 21:49












3 Answers
3






active

oldest

votes

















up vote
1
down vote



accepted










A more efficient one-pass solution would be to use a seen dict that keeps track of a list of keys that have "seen" a given value so far:



pairs = set()
seen = {}
for key, values in d.items():
for value in values:
if value in seen:
for seen_key in seen[value]:
pairs.add(frozenset((key, seen_key)))
seen.setdefault(value, ).append(key)


pairs would become:



{frozenset({'D', 'A'}), frozenset({'B', 'E'}), frozenset({'B', 'A'}), frozenset({'C', 'D'}), frozenset({'C', 'A'})}


You can then easily transform it to a set of lexicographically sorted tuples if you want:



{tuple(sorted(p)) for p in pairs}


which returns:



{('A', 'C'), ('B', 'E'), ('C', 'D'), ('A', 'D'), ('A', 'B')}





share|improve this answer




























    up vote
    2
    down vote













    Using itertools.combinations:



    from itertools import combinations

    d = {
    'C': {'123'},
    'A': {'123', '456'},
    'D': {'123'},
    'B': {'789', '456'},
    'E': {'789'}
    }

    def MyFunction(d):
    out = set()
    for i, j in combinations(d, 2):
    if d[j].intersection(d[i]) and (i, j) not in out and (j, i) not in out:
    out.add((i, j))
    return set(tuple(sorted(i)) for i in out)

    print(MyFunction(d))
    print(MyFunction(d) == {("A", "B"), ("A", "C"), ("A", "D"), ("B", "E"), ("C", "D")})


    Output is:



    {('A', 'D'), ('A', 'B'), ('B', 'E'), ('A', 'C'), ('C', 'D')}
    True


    If you consider ('A', 'C') and ('C', 'A') same, you can replace



    return set(tuple(sorted(i)) for i in out)


    with just



    return out





    share|improve this answer






























      up vote
      1
      down vote














      defaultdict + combinations



      For a brute force solution, you can invert your dictionary of sets, then use a set comprehension:



      from collections import defaultdict
      from itertools import combinations

      d = {'C': {'123'}, 'A': {'123', '456'},
      'D': {'123'}, 'B': {'789', '456'},
      'E': {'789'}}

      dd = defaultdict(set)

      for k, v in d.items():
      for w in v:
      dd[w].add(k)

      res = {frozenset(i) for v in dd.values() if len(v) >= 2 for i in combinations(v, 2)}

      print(res)

      {frozenset({'A', 'D'}), frozenset({'C', 'D'}),
      frozenset({'B', 'E'}), frozenset({'B', 'A'}),
      frozenset({'C', 'A'})}


      As you can see the items in res are frozenset objects, i.e. they aren't depending on sorting within tuples. frozenset is required instead of set since set is not hashable.






      share|improve this answer





















        Your Answer






        StackExchange.ifUsing("editor", function () {
        StackExchange.using("externalEditor", function () {
        StackExchange.using("snippets", function () {
        StackExchange.snippets.init();
        });
        });
        }, "code-snippets");

        StackExchange.ready(function() {
        var channelOptions = {
        tags: "".split(" "),
        id: "1"
        };
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function() {
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled) {
        StackExchange.using("snippets", function() {
        createEditor();
        });
        }
        else {
        createEditor();
        }
        });

        function createEditor() {
        StackExchange.prepareEditor({
        heartbeatType: 'answer',
        convertImagesToLinks: true,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        });


        }
        });














        draft saved

        draft discarded


















        StackExchange.ready(
        function () {
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53420730%2freturn-a-set-of-pairs-of-keys-from-a-dictionary-that-have-a-common-value%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        3 Answers
        3






        active

        oldest

        votes








        3 Answers
        3






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes








        up vote
        1
        down vote



        accepted










        A more efficient one-pass solution would be to use a seen dict that keeps track of a list of keys that have "seen" a given value so far:



        pairs = set()
        seen = {}
        for key, values in d.items():
        for value in values:
        if value in seen:
        for seen_key in seen[value]:
        pairs.add(frozenset((key, seen_key)))
        seen.setdefault(value, ).append(key)


        pairs would become:



        {frozenset({'D', 'A'}), frozenset({'B', 'E'}), frozenset({'B', 'A'}), frozenset({'C', 'D'}), frozenset({'C', 'A'})}


        You can then easily transform it to a set of lexicographically sorted tuples if you want:



        {tuple(sorted(p)) for p in pairs}


        which returns:



        {('A', 'C'), ('B', 'E'), ('C', 'D'), ('A', 'D'), ('A', 'B')}





        share|improve this answer

























          up vote
          1
          down vote



          accepted










          A more efficient one-pass solution would be to use a seen dict that keeps track of a list of keys that have "seen" a given value so far:



          pairs = set()
          seen = {}
          for key, values in d.items():
          for value in values:
          if value in seen:
          for seen_key in seen[value]:
          pairs.add(frozenset((key, seen_key)))
          seen.setdefault(value, ).append(key)


          pairs would become:



          {frozenset({'D', 'A'}), frozenset({'B', 'E'}), frozenset({'B', 'A'}), frozenset({'C', 'D'}), frozenset({'C', 'A'})}


          You can then easily transform it to a set of lexicographically sorted tuples if you want:



          {tuple(sorted(p)) for p in pairs}


          which returns:



          {('A', 'C'), ('B', 'E'), ('C', 'D'), ('A', 'D'), ('A', 'B')}





          share|improve this answer























            up vote
            1
            down vote



            accepted







            up vote
            1
            down vote



            accepted






            A more efficient one-pass solution would be to use a seen dict that keeps track of a list of keys that have "seen" a given value so far:



            pairs = set()
            seen = {}
            for key, values in d.items():
            for value in values:
            if value in seen:
            for seen_key in seen[value]:
            pairs.add(frozenset((key, seen_key)))
            seen.setdefault(value, ).append(key)


            pairs would become:



            {frozenset({'D', 'A'}), frozenset({'B', 'E'}), frozenset({'B', 'A'}), frozenset({'C', 'D'}), frozenset({'C', 'A'})}


            You can then easily transform it to a set of lexicographically sorted tuples if you want:



            {tuple(sorted(p)) for p in pairs}


            which returns:



            {('A', 'C'), ('B', 'E'), ('C', 'D'), ('A', 'D'), ('A', 'B')}





            share|improve this answer












            A more efficient one-pass solution would be to use a seen dict that keeps track of a list of keys that have "seen" a given value so far:



            pairs = set()
            seen = {}
            for key, values in d.items():
            for value in values:
            if value in seen:
            for seen_key in seen[value]:
            pairs.add(frozenset((key, seen_key)))
            seen.setdefault(value, ).append(key)


            pairs would become:



            {frozenset({'D', 'A'}), frozenset({'B', 'E'}), frozenset({'B', 'A'}), frozenset({'C', 'D'}), frozenset({'C', 'A'})}


            You can then easily transform it to a set of lexicographically sorted tuples if you want:



            {tuple(sorted(p)) for p in pairs}


            which returns:



            {('A', 'C'), ('B', 'E'), ('C', 'D'), ('A', 'D'), ('A', 'B')}






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Nov 21 at 22:07









            blhsing

            27.6k41335




            27.6k41335
























                up vote
                2
                down vote













                Using itertools.combinations:



                from itertools import combinations

                d = {
                'C': {'123'},
                'A': {'123', '456'},
                'D': {'123'},
                'B': {'789', '456'},
                'E': {'789'}
                }

                def MyFunction(d):
                out = set()
                for i, j in combinations(d, 2):
                if d[j].intersection(d[i]) and (i, j) not in out and (j, i) not in out:
                out.add((i, j))
                return set(tuple(sorted(i)) for i in out)

                print(MyFunction(d))
                print(MyFunction(d) == {("A", "B"), ("A", "C"), ("A", "D"), ("B", "E"), ("C", "D")})


                Output is:



                {('A', 'D'), ('A', 'B'), ('B', 'E'), ('A', 'C'), ('C', 'D')}
                True


                If you consider ('A', 'C') and ('C', 'A') same, you can replace



                return set(tuple(sorted(i)) for i in out)


                with just



                return out





                share|improve this answer



























                  up vote
                  2
                  down vote













                  Using itertools.combinations:



                  from itertools import combinations

                  d = {
                  'C': {'123'},
                  'A': {'123', '456'},
                  'D': {'123'},
                  'B': {'789', '456'},
                  'E': {'789'}
                  }

                  def MyFunction(d):
                  out = set()
                  for i, j in combinations(d, 2):
                  if d[j].intersection(d[i]) and (i, j) not in out and (j, i) not in out:
                  out.add((i, j))
                  return set(tuple(sorted(i)) for i in out)

                  print(MyFunction(d))
                  print(MyFunction(d) == {("A", "B"), ("A", "C"), ("A", "D"), ("B", "E"), ("C", "D")})


                  Output is:



                  {('A', 'D'), ('A', 'B'), ('B', 'E'), ('A', 'C'), ('C', 'D')}
                  True


                  If you consider ('A', 'C') and ('C', 'A') same, you can replace



                  return set(tuple(sorted(i)) for i in out)


                  with just



                  return out





                  share|improve this answer

























                    up vote
                    2
                    down vote










                    up vote
                    2
                    down vote









                    Using itertools.combinations:



                    from itertools import combinations

                    d = {
                    'C': {'123'},
                    'A': {'123', '456'},
                    'D': {'123'},
                    'B': {'789', '456'},
                    'E': {'789'}
                    }

                    def MyFunction(d):
                    out = set()
                    for i, j in combinations(d, 2):
                    if d[j].intersection(d[i]) and (i, j) not in out and (j, i) not in out:
                    out.add((i, j))
                    return set(tuple(sorted(i)) for i in out)

                    print(MyFunction(d))
                    print(MyFunction(d) == {("A", "B"), ("A", "C"), ("A", "D"), ("B", "E"), ("C", "D")})


                    Output is:



                    {('A', 'D'), ('A', 'B'), ('B', 'E'), ('A', 'C'), ('C', 'D')}
                    True


                    If you consider ('A', 'C') and ('C', 'A') same, you can replace



                    return set(tuple(sorted(i)) for i in out)


                    with just



                    return out





                    share|improve this answer














                    Using itertools.combinations:



                    from itertools import combinations

                    d = {
                    'C': {'123'},
                    'A': {'123', '456'},
                    'D': {'123'},
                    'B': {'789', '456'},
                    'E': {'789'}
                    }

                    def MyFunction(d):
                    out = set()
                    for i, j in combinations(d, 2):
                    if d[j].intersection(d[i]) and (i, j) not in out and (j, i) not in out:
                    out.add((i, j))
                    return set(tuple(sorted(i)) for i in out)

                    print(MyFunction(d))
                    print(MyFunction(d) == {("A", "B"), ("A", "C"), ("A", "D"), ("B", "E"), ("C", "D")})


                    Output is:



                    {('A', 'D'), ('A', 'B'), ('B', 'E'), ('A', 'C'), ('C', 'D')}
                    True


                    If you consider ('A', 'C') and ('C', 'A') same, you can replace



                    return set(tuple(sorted(i)) for i in out)


                    with just



                    return out






                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited Nov 21 at 23:21

























                    answered Nov 21 at 23:10









                    slavos1

                    365




                    365






















                        up vote
                        1
                        down vote














                        defaultdict + combinations



                        For a brute force solution, you can invert your dictionary of sets, then use a set comprehension:



                        from collections import defaultdict
                        from itertools import combinations

                        d = {'C': {'123'}, 'A': {'123', '456'},
                        'D': {'123'}, 'B': {'789', '456'},
                        'E': {'789'}}

                        dd = defaultdict(set)

                        for k, v in d.items():
                        for w in v:
                        dd[w].add(k)

                        res = {frozenset(i) for v in dd.values() if len(v) >= 2 for i in combinations(v, 2)}

                        print(res)

                        {frozenset({'A', 'D'}), frozenset({'C', 'D'}),
                        frozenset({'B', 'E'}), frozenset({'B', 'A'}),
                        frozenset({'C', 'A'})}


                        As you can see the items in res are frozenset objects, i.e. they aren't depending on sorting within tuples. frozenset is required instead of set since set is not hashable.






                        share|improve this answer

























                          up vote
                          1
                          down vote














                          defaultdict + combinations



                          For a brute force solution, you can invert your dictionary of sets, then use a set comprehension:



                          from collections import defaultdict
                          from itertools import combinations

                          d = {'C': {'123'}, 'A': {'123', '456'},
                          'D': {'123'}, 'B': {'789', '456'},
                          'E': {'789'}}

                          dd = defaultdict(set)

                          for k, v in d.items():
                          for w in v:
                          dd[w].add(k)

                          res = {frozenset(i) for v in dd.values() if len(v) >= 2 for i in combinations(v, 2)}

                          print(res)

                          {frozenset({'A', 'D'}), frozenset({'C', 'D'}),
                          frozenset({'B', 'E'}), frozenset({'B', 'A'}),
                          frozenset({'C', 'A'})}


                          As you can see the items in res are frozenset objects, i.e. they aren't depending on sorting within tuples. frozenset is required instead of set since set is not hashable.






                          share|improve this answer























                            up vote
                            1
                            down vote










                            up vote
                            1
                            down vote










                            defaultdict + combinations



                            For a brute force solution, you can invert your dictionary of sets, then use a set comprehension:



                            from collections import defaultdict
                            from itertools import combinations

                            d = {'C': {'123'}, 'A': {'123', '456'},
                            'D': {'123'}, 'B': {'789', '456'},
                            'E': {'789'}}

                            dd = defaultdict(set)

                            for k, v in d.items():
                            for w in v:
                            dd[w].add(k)

                            res = {frozenset(i) for v in dd.values() if len(v) >= 2 for i in combinations(v, 2)}

                            print(res)

                            {frozenset({'A', 'D'}), frozenset({'C', 'D'}),
                            frozenset({'B', 'E'}), frozenset({'B', 'A'}),
                            frozenset({'C', 'A'})}


                            As you can see the items in res are frozenset objects, i.e. they aren't depending on sorting within tuples. frozenset is required instead of set since set is not hashable.






                            share|improve this answer













                            defaultdict + combinations



                            For a brute force solution, you can invert your dictionary of sets, then use a set comprehension:



                            from collections import defaultdict
                            from itertools import combinations

                            d = {'C': {'123'}, 'A': {'123', '456'},
                            'D': {'123'}, 'B': {'789', '456'},
                            'E': {'789'}}

                            dd = defaultdict(set)

                            for k, v in d.items():
                            for w in v:
                            dd[w].add(k)

                            res = {frozenset(i) for v in dd.values() if len(v) >= 2 for i in combinations(v, 2)}

                            print(res)

                            {frozenset({'A', 'D'}), frozenset({'C', 'D'}),
                            frozenset({'B', 'E'}), frozenset({'B', 'A'}),
                            frozenset({'C', 'A'})}


                            As you can see the items in res are frozenset objects, i.e. they aren't depending on sorting within tuples. frozenset is required instead of set since set is not hashable.







                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Nov 21 at 21:37









                            jpp

                            86.2k194898




                            86.2k194898






























                                draft saved

                                draft discarded




















































                                Thanks for contributing an answer to Stack Overflow!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.





                                Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                                Please pay close attention to the following guidance:


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53420730%2freturn-a-set-of-pairs-of-keys-from-a-dictionary-that-have-a-common-value%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                Contact image not getting when fetch all contact list from iPhone by CNContact

                                count number of partitions of a set with n elements into k subsets

                                A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks