简体   繁体   中英

Sorting a Python list by key… while checking for string OR float?

Ok, I've got a list like this (just a sample of data):

data = {"NAME": "James", "RANK": "3.0", "NUM": "27.5" ... }

Now, if I run something like this:

sortby = "NAME" //this gets passed to the function, hence why I am using a variable sortby instead
data.sort(key=itemgetter(sortby))

I get all the strings sorted properly - alphabetically.

However, when "sortby" is any of the floating values (RANK or NUM or any other), sort is done again, alphabetically, instead of numerically, so my sorted list looks something like this then:

0.441 101.404 107.558 107.558 108.48 108.945 11.195 12.143 12.801 131.73

which is obviously wrong.

Now, how can I do a sort like that (most efficiently in terms of speed and resources/computations taken) but have it cast the value somehow to float when it's a float, and leave it as a string when it's a string... possible? And no, removing quotes from float values in the list is not an option - I don't have control over the source list, unfortunately (and I know, that would've been an easy solution).

If you want a general function which you can pass as a parameter to sort(key=XXX) , then here's a candidate complete with test:

DATA = [
    { 'name' : 'A', 'value' : '10.0' },
    { 'name' : 'B', 'value' : '2.0' },
]

def get_attr(name):
    def inner_func(o):
        try:
            rv = float(o[name])
        except ValueError:
            rv = o[name]
        return rv
    return inner_func

for attrname in ('name', 'value'):
    DATA.sort(key=get_attr(attrname))
    print "%r-sorted: %s" % (attrname, DATA)

When you run the above script, you get:

'name'-sorted: [{'name': 'A', 'value': '10.0'}, {'name': 'B', 'value': '2.0'}]
'value'-sorted: [{'name': 'B', 'value': '2.0'}, {'name': 'A', 'value': '10.0'}]

if you cant save your data properly ( floats as floats ), something like this

sorters = { "NAME" : itemgetter("NAME"), 
            "RANK" : lambda x: float(x["RANK"]),
            "NUM" : lambda x: float(x["NUM"])
}

data.sort(key=sorters[sortby])

Slightly more verbose than just passing a field name, but this is an option:

sort_by_name = lambda x: x['name']
sort_by_rank = lambda x: float(x['RANK'])
# etc...

data.sort(key=sort_by_rank)

If the data is much more dense than what you've posted, you might want a separate dictionary mapping field names to data types, and then a factory function to produce sorters suitable for the key argument to list.sort()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM