I’m using Python 2.6.2. I have a list of tuples pair which I like to sort using two nested conditions.
- The tuples are first sorted in descending count order of
fwd_count, - If the value of count is the same for more than one tuple in
fwd_count, only those tuples having equal count need to be sorted in descending order based on values inrvs_count. - The order does not matter and the positioning can be ignored, if
a) tuples have the same count infwd_countand also inrvs_count, or
a) tuples have the same count infwd_countand does not exist inrvs_count
I managed to write the following code:
pair=[((0, 12), (0, 36)), ((1, 12), (0, 36)), ((2, 12), (1, 36)), ((3, 12), (1, 36)), ((1, 36), (4, 12)), ((0, 36), (5, 12)), ((1, 36), (6, 12))]
fwd_count = {}
rvs_count = {}
for link in sorted(pair):
fwd_count[link[0]] = 0
rvs_count[link[1]] = 0
for link in sorted(pair):
fwd_count[link[0]] += 1
rvs_count[link[1]] += 1
#fwd_count {(6, 12): 1, (5, 12): 1, (4, 12): 1, (1, 36): 2, (0, 36): 2}
#rvs_count {(3, 12): 1, (1, 12): 1, (1, 36): 2, (0, 12): 1, (2, 12): 1, (0, 36): 1}
fwd_count_sort=sorted(fwd_count.items(), key=lambda x: x[1], reverse=True)
rvs_count_sort=sorted(rvs_count.items(), key=lambda x: x[1])
#fwd_count_sort [((1, 36), 2), ((0, 36), 2), ((6, 12), 1), ((5, 12), 1), ((4, 12), 1)]
#rvs_count_sort [((3, 12), 1), ((1, 12), 1), ((1, 36), 2), ((0, 12), 1), ((2, 12), 1), ((0, 36), 1)]
The result I am looking for is:
#fwd_count_sort_final [((0, 36), 2), ((1, 36), 2), ((6, 12), 1), ((5, 12), 1), ((4, 12), 1)]
Where the position of (1, 36) and (0, 36) have swapped position from the one in fwd_count_sort.
Question:
- Is there a better way to do multi condition sorting using
fwd_countandrvs_countinformation at the same time? (Only the tuples are important, the sort value need not be recorded.), or - Would I need to sort it individually for each conditions (as I did above) and try to find mean to integrate it to get the result I wanted?
I am currently working on item #2 above, but trying to learn if there are any simpler method.
This is the closest I can get to what I am looking for “Bidirectional Sorting with Numeric Values” at http://stygianvision.net/updates/python-sort-list-object-dictionary-multiple-key/ but not sure I can use that if I create a new dictionary with {tuple: {fwd_count : rvs_count}} relationship.
Update: 12 November 2012 — SOLVED
I have managed to solve this by using list. The below are the codes, hope it is useful for those whom are working to sort multi condition list.
#pair=[((0, 12), (0, 36)), ((1, 12), (1, 36)), ((2, 12), (0, 36)), ((3, 12), (1, 36)), ((1, 36), (4, 12)), ((0, 36), (5, 12)), ((1, 36), (6, 12))]
rvs_count = {}
fwd_count = {}
for link in sorted(pair):
rvs_count[link[0]] = 0
fwd_count[link[1]] = 0
for link in sorted(pair):
rvs_count[link[0]] += 1
fwd_count[link[1]] += 1
keys = []
for link in pair:
if link[0] not in keys:
keys.append(link[0])
if link[1] not in keys:
keys.append(link[1])
aggregated = []
for k in keys:
a = -1
d = -1
if k in fwd_count.keys():
a = fwd_count[k]
if k in rvs_count.keys():
d = rvs_count[k]
aggregated.append(tuple((k, tuple((a,d)) )))
def compare(x,y):
a1 = x[1][0]
d1 = x[1][1]
a2 = y[1][0]
d2 = y[1][1]
if a1 > a2:
return - a1 + a2
elif a1 == a2:
if d1 > d2:
return d1 - d2
elif d1 == d2:
return 0
else:
return d1 - d2
else:
return - a1 + a2
s = sorted(aggregated, cmp=compare)
print(s)
j = [v[0] for v in s]
print(j)
Thanks to Andre Fernandes, Brian and Duke for giving your comments on my work
If you require to swap all first (of pair) elements (and not just
(1, 36)and(0, 36)), you can dofwd_count_sort=sorted(rvs_count.items(), key=lambda x: (x[0][1],-x[0][0]), reverse=True)