Implementing this algorithm on Lists - Python
Question: Edit: Seems I made a mistake on my previous description and example so here it
is fixed.

# Latest Version

    
    
    interactions = [ ['O1', 'O3'],
                     ['O2', 'O5'],
                     ['O8', 'O10']
                     ['P3', 'P5'],
                     ['P2', 'P19'],
                     ['P1', 'P6'] ]
    

So same as before, each entry is an interaction between two parts of an
object. For example think of O and P as organisms, and O1, O8, P4, P6 ... as
sub-section to the organisms. So each interaction is between sub-sections in
the same organism, and in this list there are many organisms.

Now, the similar list:

    
    
    similar = ['O1', 'P23'],
              ['O3', 'P50'],
              ['P2', 'O40'],
              ['P19', 'O22']
    

So **O1** is similar to **P23** and **O3** is similar to **P50** AND [O1, O2]
interact thus the interaction ['P23', 'P50'] is a transformed interaction.

Likewise, **P2** is similar to **O40** and **P19** is similar to **O22** AND
[P2, P19] interact thus the interaction ['O40', 'O22'] is a transformed
interaction.

The transformed interactions will always be from the same organism, eg: [PX,
PX] or [OX, OX].

# Older Version

Let's say I have the following list:

    
    
    interactions = [ [O1, O3],
                     [O1, O8],
                     [O4, O6],
                     [O9, O2],
                     [ ... ] ]
    

what this list is meant to represent is an interaction between two objects, so
`O1 and O3` interact, etc.

Now, let's say I have a second list:

    
    
    similar = [ [O1, H33],
                [O6, O9],
                [O4, H1],
                [O2, H12],
                [ ... ] ]
    

and what this list is meant to represent is objects that are similar.

If we know objects A and B in the list `interactions` do indeed have an
intereaction, AND we know that we have an object A' that is similar to A, and
an object B' which is similar to B, then we can map the interaction from A to
B to the objects A' to B'.

For example: `O9 and O2 interact.` `O6 is similar to O9.` `H12 is similar to
O2.` `thus [O6, H12] interact.`

Note: `interactions = [ [O1, O3] ]` is the same as `[O3, O1]`, although it
would only be stored in the list `interactions` once, in either format. The
same applies to the list `similar`.

So I guess the algorithm for this would be:

  1. for every unique object A in the in fields [0] and [1] in list `similar`,
  2. fetch a list B of interactions from the list `interactions`.
  3. check for entries in `similar` where A is similar to some object A', and B is similar to some object B'.
  4. map the interaction between A' and B'.

Edit: Code for this version.

# Code

    
    
    from collections import defaultdict
    interactions = [ ['O1', 'O3'],
                     ['O1', 'O8'],
                     ['O4', 'O6'],
                     ['O9', 'O2'] ]
    
    similar = [ ['O1', 'H33'],
                ['O6', 'O9'],
                ['O4', 'H1'],
                ['O2', 'H12'] ]
    
    def list_of_lists_to_dict(list_of_lists):
      d = defaultdict(list)
      for sublist in list_of_lists:
        d[sublist[0]].append(sublist[1])
        d[sublist[1]].append(sublist[0])
      return d
    
    interactions_dict = list_of_lists_to_dict(interactions)
    similar_dict = list_of_lists_to_dict(similar)
    
    
    for key, values in interactions_dict.items():
      print "{0} interacts with: {1}".format(key, ', '.join(values))
        if key in similar_dict:
          print " {0} is similar to: {1}".format(key, ', '.join(similar_dict[key]))
          forward = True
      for value in values:
        if value in similar_dict:
          print " {0} is similar to: {1}".format(value, ', '.join(similar_dict[value]))
          reverse = True
          if forward and reverse:
            print "     thus [{0}, {1}] interact!".format(', '.join(similar_dict[key]), 
                 ',  '.join(similar_dict[value]))
      forward = reverse = False
    

Alright, that's all the background information.

So, I'm pretty new to python and I think I could implement this with a bunch
of nested for loops and conditions, however I was wondering if there is a more
elegant, pythonic way of going about this.

If read all of this, thank you for you time! :)


Answer: This should do it

    
    
    _interactions = set([ (O1, O3),
                     (O1, O8),
                     (O4, O6),
                     (O9, O2),
                     ( ... ) ])
    interactions = set()
    for i,j in _interactions:
        if (i,j) not in interactions and (j,i) not in interactions:
            interactions.add((i,j))
    
    _similar = set([ (O1, H33),
                (O6, O9),
                (O4, H1),
                (O2, H12),
                ( ... ) ])
    similar = set()
    for i,j in _similar:
        if (i,j) not in similar and (j,i) not in similar:
            similar. add((i,j))
    
    answer = set()
    for i,j in interactions:
        a = random.choice([x for x,y in similar if y==i] + [y for x,y in a if x==i]) # assuming that everything is similar to at least one thing
        b = random.choice([x for x,y in similar if y==j] + [y for x,y in a if x==j]) # assuming same
        if (a,b) not in answer and (b,a) not in answer:
            answer.add((a,b))
    

