with open(sys.argv[1]) as f:
lst = list(f.readline().strip())
sortedLst = sorted(lst, key = lambda x: (x.lower(), x.swapcase()))
print(lst)
print(sortedLst)
The word I am using as an example is 'ThatCcer'. My outputs are ['T', 'h', 'a', 't', 'C', 'c', 'e', 'r'] for lst and my outputs are ['a', 'c', 'C', 'e', 'h', 'r', 't', 'T'] for sortedLst.
This is exactly what I am going for - to sort a word in alphabetical order with lower case letters taking precedence over upper case.
What I am trying to achieve is to match other 8-letter inputs by sorting them in the exact way that I have sorted ThatCcher. How would I go about achieving this?
EDIT: I am being told the question is unclear - my apologies but it is a bit difficult to explain so I will try again.
By sorting ThatCcer to become acCehrtT, lst[0] ('T') took the position of sortedLst[7], lst[1] ('h') took the position of sortedLst[4], and so on...
This is the history I want to record and so that given any other string can copy the steps that 'ThatCcer' took, for example: s = ['h', 'o', 'w', 'e', 'v', 'e', 'r', 's']
I want s[0] to to take its' position in sortedS[7], just like ThatCcer did.
I hope this made it a little clearer!
CodePudding user response:
IIUC, you want to achieve a behavior similar to that of numpy.argsort
.
You can sort a range based on your criteria, and use it to reindex any string:
lst = ['T', 'h', 'a', 't', 'C', 'c', 'e', 'r']
idx = list(range(len(lst)))
sorted_idx = sorted(idx, key=lambda x: (lst[x].lower(), lst[x].swapcase()))
# [2, 5, 4, 6, 1, 7, 3, 0]
# now use the index to sort
[lst[i] for i in sorted_idx]
# ['a', 'c', 'C', 'e', 'h', 'r', 't', 'T']
# keep the same order on another string
lst2 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
[lst2[i] for i in sorted_idx]
# ['c', 'f', 'e', 'g', 'b', 'h', 'd', 'a']
Another approach using zip
:
lst = ['T', 'h', 'a', 't', 'C', 'c', 'e', 'r']
lst2 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
list(zip(*sorted(zip(lst, lst2), key=lambda x: (x[0].lower(), x[0].swapcase()))))
# or as individual lists
# (lst_sorted, lst2_sorted) = list(zip(*sorted(zip(lst, lst2),
# key=lambda x: # (x[0].lower(), x[0].swapcase()))))
output:
[('a', 'c', 'C', 'e', 'h', 'r', 't', 'T'),
('c', 'f', 'e', 'g', 'b', 'h', 'd', 'a')]
CodePudding user response:
Sort the enumerated string on the string characters, then separate the (sorted) indices and characters; use operator.itemgetter to create a callable that you can re-use.
import operator
def f(thing):
s_lst = sorted(enumerate(thing),key = lambda x: (x[1].lower(), x[1].swapcase()))
argsort = operator.itemgetter(*[x[0] for x in s_lst])
s_lst = [x[1] for x in s_lst]
return s_lst,argsort
>>> s_lst, argsort = f('ThatCcerCTaa')
>>> s_lst
['a', 'a', 'a', 'c', 'C', 'C', 'e', 'h', 'r', 't', 'T', 'T']
>>> argsort('ThatCcerCTaa')
('a', 'a', 'a', 'c', 'C', 'C', 'e', 'h', 'r', 't', 'T', 'T')
>>> argsort
operator.itemgetter(2, 10, 11, 5, 4, 8, 6, 1, 7, 3, 0, 9)
>>>