python convert strings to int and order list by string first in descending, integer in ascending?

Question:

I’ve got a list that looks like this:
["A", "X", "B", "3", "5", "1"]

I’m trying to find a way to sort this so it looks like this:
["X", "B", "A", 1, 3, 5]

I created a small function to convert the list strings to integer where appropriate:

def convert_list(list_to_convert: list) -> list:
    """If a list contains strings where some should be ints, this attempts to
    convert them to ints where appropriate"""
    converted_list = []
    for item in list_to_convert:
        try:
            item = int(item)
        except ValueError:
            pass
        converted_list.append(item)
    return converted_list

That gives me ["A", "X", "B", 3, 5, 1]

But I’m not sure how to get this list to sort by the letters in descending, while sorting the integers in ascending.

I’ve tried this:

    sorted_int_grade_list = sorted(
        ordered_grade_list, key=lambda i: (isinstance(i, int), i)
    )

But that gives me ["A", "B", "X", 1, 3, 5]
(alpha is wrong direction, integers are correct)

I’m not sure how to sort this in two different fashions – any ideas would be helpful.

Asked By: Hanny

||

Answers:

You can first separate them into two lists, sort each of them, and then merge them:

lst = ["A", "X", "B", "3", "5", "1"]

letters = []
numbers = []

for x in lst:
    try:
        numbers.append(int(x))
    except ValueError:
        letters.append(x)

output = [*sorted(letters, reverse=True), *sorted(numbers)] # uses generalized unpacking: PEP 448

print(output) # ['X', 'B', 'A', 1, 3, 5]
Answered By: j1-lee

Here’s an example sort func that’d do what you’d want

def alphanum_sortfunc(alphanum):
    is_int = isinstance(alphanum, int)

    # ints in ascending, strings in descending
    order_key = alphanum if is_int else -ord(alphanum)

    # tuple-based sorting, sort first by is_int, then by order_key
    return (is_int, order_key)

Which you would use like:

sorted(["A", "X", "B", 3, 5, 1], key=alphanum_sortfunc)
#=> ['X', 'B', 'A', 1, 3, 5]
Answered By: Kache

You can create a lookup table:

import string 

lu={c:i for i,c in enumerate(string.ascii_uppercase[::-1]+string.digits)}

# {'Z': 0, 'Y': 1, 'X': 2, 'W': 3, 'V': 4, 'U': 5, 'T': 6, 'S': 7, 'R': 8, 'Q': 9, 'P': 10, 'O': 11, 'N': 12, 'M': 13, 'L': 14, 'K': 15, 'J': 16, 'I': 17, 'H': 18, 'G': 19, 'F': 20, 'E': 21, 'D': 22, 'C': 23, 'B': 24, 'A': 25, '0': 26, '1': 27, '2': 28, '3': 29, '4': 30, '5': 31, '6': 32, '7': 33, '8': 34, '9': 35}

Then sort based on that:

li=["A", "X", "B", "3", "5", "1"]

>>> sorted(li, key=lambda e: lu.get(e,-1))
['X', 'B', 'A', '1', '3', '5']

Alternatively, you can write a lambda to reverse if a digit and normal order if an int:

>>> sorted(li, key=lambda e: int(e) if e.isdigit() else -ord(e))
['X', 'B', 'A', '1', '3', '5']

Then in either case, convert the digits to ints:

>>> [int(x) if x.isdigit() else x for x in sorted(li, key=lambda e: lu.get(e,-1))]
['X', 'B', 'A', 1, 3, 5]
Answered By: dawg
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.