3

I'm trying to sort a string (to make a genotype for a punnetsquare). My current implementation is:

unsorted_genotype = 'ABaB'
sorted_genotype = sorted(list(unsorted_genotype))
sorted_string = ''.join(sorted_genotype)

It outputs

'ABBa'

Though, I would want and expect:

'AaBB'

How can I change or fix this?

bcye
  • 758
  • 5
  • 22
  • 3
    Possible duplicate of [case-insensitive list sorting, without lowercasing the result?](https://stackoverflow.com/questions/10269701/case-insensitive-list-sorting-without-lowercasing-the-result) – ic3b3rg Dec 18 '18 at 21:49

2 Answers2

6

You can specify a sorting key and use the sorting for tuples:

[(1,1),(1,2)]: Tuples are sorted by 1st element, on equality by 2nd to nth:

unsorted = 'ABaB'
s = sorted(unsorted, key= lambda x:(x.lower(),x))  
print(''.join(s))  # 'AaBB'

This ensures it is first sorted by the 'lower' character - grouping a and A together and then by the actual character afterwards so they occure sorted as well: ABaaAAaAaAAAB => AAAAAAAaaaaBB

Readups:

A simple key = str.lower as suggested in the allegated dupe does not group A to A and a to a which would be nice to have for Prunnet squares


If you had them rather stay in order of occurence then grouping lower- and uppercase together, you can use:

unsorted = 'ABaaAAaAaAAAB'
s = sorted(unsorted, key=str.lower)  # not by tuple, just by lower
print(''.join(s))  

results in keeping the elements "in order":

AaaAAaAaAAABB   # instead of  AAAAAAAaaaaBB

and is described in case-insensitive list sorting, without lowercasing the result?

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
2

You can pass in a key to the sorting function:

unsorted_genotype = 'ABaB'
sorted_genotype = sorted(unsorted_genotype, key=lambda x: x.lower())
''.join(sorted_genotype)

'AaBB'
G. Anderson
  • 5,815
  • 2
  • 14
  • 21