How can I sort a list that has a float in string format with a non-numeric value?

Viewed 120

I have a list like this

data = [('£3.46', 'I001'), ('£10.46', 'I002')] 

I want to sort this list with

data.sort()

however the sorted list puts £10.46 before £3.46, I'm assuming this is because the data is a string and £1 comes before £3.
I have tried looking at lambda functions but I can't get my head around it.

3 Answers

One option is to strip "£" and convert the number to float as a sorting key:

data.sort(key=lambda x: float(x[0].lstrip('£')))
print(data)

Output:

[('£3.46', 'I001'), ('£10.46', 'I002')]

You could achieve that in this simple way:

data = [('£10.46', 'I002'), ('£3.46', 'I001')]
def sort_tuple(item):
    return float(item[0][1:])

print(sorted(data, key=sort_tuple))

Output:

[('£3.46', 'I001'), ('£10.46', 'I002')]

Process finished with exit code 0

This is a general approach with some limitations, but should work in a wide variety of similar situations.

import re

def float_then_text(values):
    '''Convert [str, str, ...] to [(float, str), (float, str), ...]'''
    return [(float(re.sub(r'[^\d.]+', '', text)), text) for
for text in values]

data = [('£3.46', 'I001'), ('£10.46', 'I002')]

data.sort(key=float_then_text)

The function float_then_text will convert from ('£3.46', 'I001') to [(3.46, '£3.46'), (1.0, 'I001')] and so on.

Including the text in the keys is optional, but ensures that values with different units get their units sorted in the same order each time as well.

Related