1

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).

3 Answers 3

7

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'}]
Sign up to request clarification or add additional context in comments.

1 Comment

+1 — Very DWIMish, and could probably be extended to other types fairly easily.
4

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])

3 Comments

I like that... never thought of a separate dictionary for sort types. Thanks! The only issue is that there are 50+ columns that I need to cast to float like this, but it is the smoothest approach so far...
Check out my answer, no need for a separate dictionary. This is a good answer, but you do have to set up that 50-entry dict...
+1 — I can certainly see this getting cumbersome as your column count grows, but I really like both the clarity and flexibility.
0

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()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.