2

I have the following data: unsorted data

I want to sort this data by first_pass (reverse), level, cat (reverse), acc1. After sorting it should be in this order: sorted data

Here is my the setup in Python:

import math
from operator import attrgetter

class Problem:
    def __init__(self, num, first_pass, cat, acc1):
        self.num = num
        self.first_pass = first_pass
        self.cat = cat
        self.acc1 = acc1
    def level(self):
        return math.ceil((1-self.acc1)*10)
    def __repr__(self):
        return "<Num:%s 1stPass:%s Cat:%s Acc1:%s Level:%s>" % (self.num, self.first_pass, self.cat, self.acc1, self.level())


p = [
Problem(1,1,2,0.582),
Problem(2,1,2,0.44),
Problem(3,0,2,0.857),
Problem(4,0,2,0.707),
Problem(5,0,2,0.826),
Problem(6,0,1,0.781),
Problem(7,0,1,0.653),
Problem(8,1,2,0.492),
Problem(9,0,2,0.893),
Problem(10,0,1,0.582),
Problem(11,0,2,0.378),
Problem(12,0,2,0.515),
Problem(13,0,0,0.958),
Problem(14,0,1,0.633),
Problem(15,0,1,0.813),
Problem(16,0,2,0.793),
Problem(17,0,2,0.692)
]

# p.sort ??

What is the sort command for this type of sort? Thanks!

4
  • Please provide what you've already tried and a specific problem you've run into. SO is not a code writing service, but instead a service where you can ask specific questions and get specific answers.
    – Darendal
    Commented Oct 22, 2015 at 19:48
  • The sorted function accepts a key argument which you can pass your function as this arg.
    – Mazdak
    Commented Oct 22, 2015 at 19:49
  • sorted(p,key = lambda x: x.attribute) will sort it by attribute
    – R Nar
    Commented Oct 22, 2015 at 19:50
  • and could you please not post the data in form of a jpg!?
    – user3850
    Commented Oct 22, 2015 at 19:50

3 Answers 3

2

The key kwarg to sort(ed) is probably most useful here, and there's a relatively convenient trick for reverse sorting numeric values:

p.sort(key = lambda x: (-x.first_pass, x.level(), -x.cat, x.acc1))
4
  • why "foo * -1" instead of "-foo"?
    – user3850
    Commented Oct 22, 2015 at 19:53
  • @hop - force of habit?
    – g.d.d.c
    Commented Oct 22, 2015 at 19:55
  • actually this returns the wrong order. It returns problem 15 as the 4th in the sort but it should be problem 13.
    – jwasher
    Commented Oct 22, 2015 at 20:50
  • @jwaster - sorry, I overlooked that .level was a function, not a property. You'll either want to call the function (like my edit) or make it a @property. Either way, this approach can still be used.
    – g.d.d.c
    Commented Oct 22, 2015 at 21:31
2

Use sorted. Here is good tutorial for using sorted. Try this:

from operator import attrgetter

s = sorted(p, key=attrgetter('acc1'))
s = sorted(s, key=attrgetter('cat'), reverse=True)
s = sorted(s, key=lambda problem: problem.level())
s = sorted(s, key=attrgetter('first_pass'), reverse=True)

it will sort data by first_pass (reverse), level, cat (reverse), acc1. But you must do it inversely. Here is output of s as you want:

[<Num:1 1stPass:1 Cat:2 Acc1:0.582 Level:5>,
 <Num:2 1stPass:1 Cat:2 Acc1:0.44 Level:6>,
 <Num:8 1stPass:1 Cat:2 Acc1:0.492 Level:6>,
 <Num:13 1stPass:0 Cat:0 Acc1:0.958 Level:1>,
 <Num:5 1stPass:0 Cat:2 Acc1:0.826 Level:2>,
 <Num:3 1stPass:0 Cat:2 Acc1:0.857 Level:2>,
 <Num:9 1stPass:0 Cat:2 Acc1:0.893 Level:2>,
 <Num:15 1stPass:0 Cat:1 Acc1:0.813 Level:2>,
 <Num:4 1stPass:0 Cat:2 Acc1:0.707 Level:3>,
 <Num:16 1stPass:0 Cat:2 Acc1:0.793 Level:3>,
 <Num:6 1stPass:0 Cat:1 Acc1:0.781 Level:3>,
 <Num:17 1stPass:0 Cat:2 Acc1:0.692 Level:4>,
 <Num:14 1stPass:0 Cat:1 Acc1:0.633 Level:4>,
 <Num:7 1stPass:0 Cat:1 Acc1:0.653 Level:4>,
 <Num:12 1stPass:0 Cat:2 Acc1:0.515 Level:5>,
 <Num:10 1stPass:0 Cat:1 Acc1:0.582 Level:5>,
 <Num:11 1stPass:0 Cat:2 Acc1:0.378 Level:7>]
1

Python's sorted function uses a stable sort, so if you want to sort on multiple fields you can use multiple sorts to do this. For example, if have a list of people and you want them sorted by last name, with first name as a secondary sort, you'd do the sort by first name first.

Since I happen to actually have this file open at the moment, you can try this:

def sorted_by(collection, lambdas, reverse):
    for l in lambdas:
        collection = sorted(collection, key=l, reverse=reverse)
    return collection

where lambdas is a list of ordering functions.

Not the answer you're looking for? Browse other questions tagged or ask your own question.