Sorting a list of objects by multiple attributes

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Steve Bergman

    Sorting a list of objects by multiple attributes

    Hi,

    I am trying to come up with a clean and simple way to sort a list of
    objects (in this case SQLObject instances) by multiple attributes.

    e.g. a Person object may have an age, a lastName, and a firstName.

    I'd like to be able to arbitrarily sort by any combination of those in
    any order.

    I would especially like it to be clear and simple, since I am
    converting a web app from using SQL to using an ORM only and so the
    sorting will actually be controlled by variables coming from SELECTs in
    a web form. In SQL this is easy enough to accomplish, and I can do it
    in python with L.sort(key=lamb da i: i.whatever). But for the multiple
    attribute case, I'm at a bit of a loss.

    Thanks for any help.

    -Steve

  • gry@ll.mit.edu

    #2
    Re: Sorting a list of objects by multiple attributes

    For multiple keys the form is quite analogous:

    L.sort(key=lamb da i: (i.whatever, i.someother, i.anotherkey))

    I.e., just return a tuple with the keys in order from your lambda.
    Such tuples sort nicely.

    -- George Young

    Comment

    • nghoffma

      #3
      Re: Sorting a list of objects by multiple attributes

      If you are lambda-phobic (as I am) this should also work for an
      arbitrary set of attributes:

      attrs = 'attr1 attr2 attr3'.split()
      sortlist = [[getattr(o,a) for a in attrs] + [o] for o in objects]
      sorted_objects = [x[-1] for x in sorted(sortlist )]

      -Noah

      Comment

      • Kent Johnson

        #4
        Re: Sorting a list of objects by multiple attributes

        gry@ll.mit.edu wrote:[color=blue]
        > For multiple keys the form is quite analogous:
        >
        > L.sort(key=lamb da i: (i.whatever, i.someother, i.anotherkey))
        >
        > I.e., just return a tuple with the keys in order from your lambda.
        > Such tuples sort nicely.[/color]

        In Python 2.5 you can do this with operator.attrge tter():

        L.sort(key=oper ator.attrgetter ('whatever', 'someother', 'anotherkey'))

        Kent

        Comment

        • Scott David Daniels

          #5
          Re: Sorting a list of objects by multiple attributes

          Kent Johnson wrote:[color=blue]
          > In Python 2.5 you can do this with operator.attrge tter():
          > L.sort(key=oper ator.attrgetter ('whatever', 'someother', 'anotherkey'))[/color]

          Note: this is also available in Python 2.4

          --Scott David Daniels
          scott.daniels@a cm.org

          Comment

          • Kent Johnson

            #6
            Re: Sorting a list of objects by multiple attributes

            Scott David Daniels wrote:[color=blue]
            > Kent Johnson wrote:[color=green]
            >> In Python 2.5 you can do this with operator.attrge tter():
            >> L.sort(key=oper ator.attrgetter ('whatever', 'someother', 'anotherkey'))[/color]
            >
            > Note: this is also available in Python 2.4[/color]

            No, the ability to specify more than one attribute name, making a getter
            that returns a tuple, is a Python 2.5 enhancement. In 2.4:

            In [1]: import operator

            In [2]: operator.attrge tter('whatever' , 'someother', 'anotherkey')
            ------------------------------------------------------------
            Traceback (most recent call last):
            File "<ipython console>", line 1, in ?
            TypeError: attrgetter expected 1 arguments, got 3

            Kent

            Comment

            • Raymond Hettinger

              #7
              Re: Sorting a list of objects by multiple attributes

              [George Young][color=blue][color=green]
              >> For multiple keys the form is quite analogous:
              >>
              >> L.sort(key=lamb da i: (i.whatever, i.someother, i.anotherkey))[/color][/color]

              [Noah][color=blue]
              > If you are lambda-phobic (as I am) this should also work for an
              > arbitrary set of attributes:
              >
              > attrs = 'attr1 attr2 attr3'.split()
              > sortlist = [[getattr(o,a) for a in attrs] + [o] for o in objects]
              > sorted_objects = [x[-1] for x in sorted(sortlist )][/color]

              The cult of lambda avoidance has lost contact with reality. Some
              Pythonistas now habitually twist their code into knots rather than use
              lambda. The above code fragment is a case in point -- it is shocking
              that the poster deems the three-line rewrite as an improvement on
              George's clear and succinct code fragment.

              Lambda avoidance is rooted in two things, an aversion to the keyword
              name and an observation that misuse can result in atrocious code. Also,
              some of the use cases have fallen by the wayside with the introduction
              of listcomps, genexps, and operator.attrge tter. Still, some use cases
              remain and there is no reason to mangle your code in the name of a
              foolish psuedo-principle.

              My advice: use lambda when appropriate and don't feel guilty about it

              Comment

              • Scott David Daniels

                #8
                Re: Sorting a list of objects by multiple attributes

                Kent Johnson wrote:[color=blue]
                > Scott David Daniels wrote:[color=green]
                >> Kent Johnson wrote:[color=darkred]
                >>> In Python 2.5 you can do this with operator.attrge tter():
                >>> L.sort(key=oper ator.attrgetter ('whatever', 'someother', 'anotherkey'))[/color]
                >>
                >> Note: this is also available in Python 2.4[/color]
                >
                > No, the ability to specify more than one attribute name, making a getter
                > that returns a tuple, is a Python 2.5 enhancement.[/color]

                Yup, sorry about that. When I installed 2.5a1 the shortcuts I used for
                2.4 got switched w/o my noticing (I did try it first). I have now made
                my 2.4 shortcuts more explicit (so the next time I'll do this stupid
                thing is likely on 2.6).

                --
                -Scott David Daniels
                scott.daniels@a cm.org

                Comment

                • nghoffma

                  #9
                  Re: Sorting a list of objects by multiple attributes

                  I'm sure my avoidance of lambdas as due as much to laziness as
                  adherence to principle. This is a good opportunity to learn about them.


                  I suggested the above because it wasn't obvious to me how one would
                  pass the arbitrary set of attributes to the lambda expression (and I
                  envisioned them being specified as strings in this case, since the set
                  of attributes will be coming from a web form).

                  So what about the following (attrgetter aside)?

                  attrs = 'attr1 attr2 attr3'.split()
                  L.sort(key=lamb da i: [getattr(i,a) for a in attrs])

                  -Noah

                  Comment

                  • Azolex

                    #10
                    Re: Sorting a list of objects by multiple attributes

                    Raymond Hettinger wrote:[color=blue]
                    >
                    > The cult of lambda avoidance has lost contact with reality. [...]
                    > Lambda avoidance is rooted in two things, an aversion to the keyword
                    > name [...][/color]

                    Let's push the diagnosis a bit further : the aversion to the keyword
                    "lambda" has to do with the fact that it ignores the english word used
                    by all non-geeks to convey the meaning, eg "given"

                    Comment

                    • Raymond Hettinger

                      #11
                      Re: Sorting a list of objects by multiple attributes

                      Azolex:[color=blue]
                      > Let's push the diagnosis a bit further : the aversion to the keyword
                      > "lambda" has to do with the fact that it ignores the english word used
                      > by all non-geeks to convey the meaning, eg "given"[/color]

                      Right. However, Guido has said that lambda is here to stay,
                      so it's time to get over it.


                      Raymond

                      Comment

                      • Raymond Hettinger

                        #12
                        Re: Sorting a list of objects by multiple attributes

                        [Noah][color=blue]
                        > I suggested the above because it wasn't obvious to me how one would
                        > pass the arbitrary set of attributes to the lambda expression (and I
                        > envisioned them being specified as strings in this case, since the set
                        > of attributes will be coming from a web form).
                        >
                        > So what about the following (attrgetter aside)?
                        >
                        > attrs = 'attr1 attr2 attr3'.split()
                        > L.sort(key=lamb da i: [getattr(i,a) for a in attrs])[/color]

                        When starting with attribute names in a list of strings,
                        this code looks fine. The Py2.5 version of attrgetter
                        will be even cleaner:

                        L.sort(key=attr getter(*attrs))

                        Comment

                        • Azolex

                          #13
                          Re: Sorting a list of objects by multiple attributes

                          Raymond Hettinger wrote:[color=blue]
                          > Azolex:[color=green]
                          >> Let's push the diagnosis a bit further : the aversion to the keyword
                          >> "lambda" has to do with the fact that it ignores the english word used
                          >> by all non-geeks to convey the meaning, eg "given"[/color]
                          >
                          > Right. However, Guido has said that lambda is here to stay,
                          > so it's time to get over it.[/color]

                          You are saying lambda is a given ? ;)

                          I've not observed the BDFL's pronouncement, so I have to ask : was it
                          clear from his words that he meant the actual keyword, or could it be he
                          just meant the construct while refering to it by the keyword ?

                          Comment

                          Working...