Your problem is all about relation in discrete mathematics that all the combinations pairs in your arrays have transitive relation together which means that if a>b and b>c then a>c
. Because of that, you can create the following lists , so in a set with length 5 the smallest element should be in 4 of these pairs --if we have such number of pairs for one. So first we need to create these pairs that are grouped by the first element, for that we can use groupby
and chain
functions from itertools
module :
>>> from itertools import combinations,chain,groupby
>>> from operator import itemgetter
>>> l1= [list(g) for _,g in groupby(sorted(chain.from_iterable(combinations(i,2) for i in [x,y,z])),key=itemgetter(0))]
[[('one', 'four'), ('one', 'four'), ('one', 'three'), ('one', 'two')], [('three', 'five'), ('three', 'four')], [('two', 'five'), ('two', 'four'), ('two', 'three')]]
So if we have the groups with len 4 ,3 ,2, 1 then we have found the answer but if we didn't find such sequence we can do the preceding calculation reversely to find our elements with this logic that if we find a relation group with len 4 its the biggest number and ...!
>>> l2= [list(g) for _,g in groupby(sorted(chain.from_iterable(combinations(i,2) for i in [x,y,z]),key=itemgetter(1)),key=itemgetter(1))]
[[('two', 'five'), ('three', 'five')], [('one', 'four'), ('two', 'four'), ('one', 'four'), ('three', 'four')], [('two', 'three'), ('one', 'three')], [('one', 'two')]]
So we can do the following :
Note that we need to use set(zip(*i)[1])
to get the set of elements that our specific elements is in relation with them,then use len
to calculate the number of those elements.
>>> [(i[0][0],len(set(zip(*i)[1]))) for i in l1]
[('one', 3), ('three', 2), ('two', 3)]
>>> [(i[0][1],len(set(zip(*i)[0]))) for i in l2]
[('five', 2), ('four', 3), ('three', 2), ('two', 1)]
In first part we found the 4,2,3 so now we just need to find the 1 that its could be four or five
.now we go to second part that we need to find a sequence with length 4 or 3
that the four
is 3 so the 4th element has been found thus 5th element should be five
.
Edit: as a more elegant and faster way you can do the job with collections.defaultdict
:
>>> from collections import defaultdict
>>> d=defaultdict(set)
>>> for i,j in chain.from_iterable(combinations(i,2) for i in [x,y,z]) :
... d[i].add(j)
...
>>> d
defaultdict(<type 'set'>, {'three': set(['four', 'five']), 'two': set(['four', 'five', 'three']), 'one': set(['four', 'two', 'three'])})
>>> l1=[(k,len(v)) for k,v in d.items()]
>>> l1
[('three', 2), ('two', 3), ('one', 3)]
>>> d=defaultdict(set)
>>> for i,j in chain.from_iterable(combinations(i,2) for i in [x,y,z]) :
... d[j].add(i) #create dict reversely
...
>>> l2=[(k,len(v)) for k,v in d.items()]
>>> l2
[('four', 3), ('five', 2), ('two', 1), ('three', 2)]