split up a list by condition?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Reinhold Birkenfeld

    split up a list by condition?

    Hi,

    while writing my solution for "The python way?", I came across this fragment:

    vees = [c for c in wlist[::-1] if c in vocals]
    cons = [c for c in wlist[::-1] if c not in vocals]

    So I think: Have I overlooked a function which splits up a sequence into two,
    based on a condition? Such as

    vees, cons = split(wlist[::-1], lambda c: c in vocals)

    Reinhold
  • Grooooops

    #2
    Re: split up a list by condition?

    Reinhold,
    Thanks for your response in the previous thread.
    Yours is an interesting question. I haven't come up with a solution,
    but I did realize that in the previous problem, the source 'word'
    doesn't really need to stay intact...
    So perhaps a solution along these lines?
    [color=blue][color=green][color=darkred]
    >>> for a in enumerate(wlist ):[/color][/color][/color]
    .... if a[1] in vowels:
    .... vees.append(wli st.pop(a[0]))

    I don't know if it's possible to cram a 'pop' command into the single
    line solution though.

    I look forward to seeing other tricks to this end... :)

    Comment

    • gene tani

      #3
      Re: split up a list by condition?

      Sounds like itertools.group by() is what you're looking for, just sort
      your sequence on the grouping func that you will pass as 2nd arg to
      groupby(), before you pass the sequence to groupby()

      The official home of the Python Programming Language



      Comment

      • Raymond Hettinger

        #4
        Re: split up a list by condition?

        >> while writing my solution for "The python way?", I came across this fragment:[color=blue][color=green]
        >> vees = [c for c in wlist[::-1] if c in vocals]
        >> cons = [c for c in wlist[::-1] if c not in vocals]
        >>
        >> So I think: Have I overlooked a function which splits up a sequence
        >> into two, based on a condition[/color][/color]

        Trying to compress too much into one line is not "the python way" ;-)


        vees, cons = [], []
        for c in reversed(wlist) :
        if c in vocals:
        vees.append(c)
        else:
        cons.append(c)

        Comment

        • Duncan Booth

          #5
          Re: split up a list by condition?

          Reinhold Birkenfeld wrote:
          [color=blue]
          > Hi,
          >
          > while writing my solution for "The python way?", I came across this
          > fragment:
          >
          > vees = [c for c in wlist[::-1] if c in vocals]
          > cons = [c for c in wlist[::-1] if c not in vocals]
          >
          > So I think: Have I overlooked a function which splits up a sequence
          > into two, based on a condition? Such as
          >
          > vees, cons = split(wlist[::-1], lambda c: c in vocals)
          >
          > Reinhold[/color]

          If you really are being charged by the number of newline characters in your
          code you could write:
          [color=blue][color=green][color=darkred]
          >>> wlist = list('The quick brown fox')
          >>> vowels = 'aeiuo'
          >>> cons = []
          >>> vees = [ c for c in wlist if c in vowels or cons.append(c) ]
          >>> cons[/color][/color][/color]
          ['T', 'h', ' ', 'q', 'c', 'k', ' ', 'b', 'r', 'w', 'n', ' ', 'f', 'x'][color=blue][color=green][color=darkred]
          >>> vees[/color][/color][/color]
          ['e', 'u', 'i', 'o', 'o'][color=blue][color=green][color=darkred]
          >>> cons = []
          >>> vees = [ c for c in wlist[::-1] if c in vowels or cons.append(c) ]
          >>> cons[/color][/color][/color]
          ['x', 'f', ' ', 'n', 'w', 'r', 'b', ' ', 'k', 'c', 'q', ' ', 'h', 'T'][color=blue][color=green][color=darkred]
          >>> vees[/color][/color][/color]
          ['o', 'o', 'i', 'u', 'e']

          but every penny you save writing a one liner will be tuppence extra on
          maintenance.

          Comment

          • Reinhold Birkenfeld

            #6
            Re: split up a list by condition?

            Raymond Hettinger wrote:[color=blue][color=green][color=darkred]
            >>> while writing my solution for "The python way?", I came across this fragment:
            >>> vees = [c for c in wlist[::-1] if c in vocals]
            >>> cons = [c for c in wlist[::-1] if c not in vocals]
            >>>
            >>> So I think: Have I overlooked a function which splits up a sequence
            >>> into two, based on a condition[/color][/color]
            >
            > Trying to compress too much into one line is not "the python way" ;-)[/color]

            I know (there is a Guido quote about this, I just lost the source...)
            [color=blue]
            > vees, cons = [], []
            > for c in reversed(wlist) :
            > if c in vocals:
            > vees.append(c)
            > else:
            > cons.append(c)
            >[/color]

            Well, I've found a uglier solution,

            vees, cons = [], []
            [(vees, cons)[ch in vocals].append(ch) for ch in wlist]

            Reinhold

            Comment

            • Reinhold Birkenfeld

              #7
              Re: split up a list by condition?

              Duncan Booth wrote:[color=blue]
              > Reinhold Birkenfeld wrote:
              >[color=green]
              >> Hi,
              >>
              >> while writing my solution for "The python way?", I came across this
              >> fragment:
              >>
              >> vees = [c for c in wlist[::-1] if c in vocals]
              >> cons = [c for c in wlist[::-1] if c not in vocals]
              >>
              >> So I think: Have I overlooked a function which splits up a sequence
              >> into two, based on a condition? Such as
              >>
              >> vees, cons = split(wlist[::-1], lambda c: c in vocals)
              >>
              >> Reinhold[/color]
              >
              > If you really are being charged by the number of newline characters in your
              > code you could write:[/color]

              [...]
              [color=blue]
              > but every penny you save writing a one liner will be tuppence extra on
              > maintenance.[/color]

              This is clear. I actually wanted to know if there is a function which I
              overlooked which does that, which wouldn't be a maintenance nightmare at all.

              Reinhold

              Comment

              • Grooooops

                #8
                Re: split up a list by condition?

                > vees, cons = [], [][color=blue]
                > [(vees, cons)[ch in vocals].append(ch) for ch in wlist][/color]

                Wow, that's horribly twisted Reinhold...
                I spent about an hour last night trying something similar, to no end...
                :)

                Neat tricks people...
                I like Duncan's use of "or" to solve it.
                I didn't see that in the python docs on list comprehension.
                Very cool.

                There is a special place in my heart for obfuscated Python,
                but of course, not in production code if there is a clearer solution
                available.

                Comment

                • Paul McGuire

                  #9
                  Re: split up a list by condition?

                  Re-run this with the input string "The quick brown fox is named
                  'Aloysius'." and we discover that 'A', 'y', "'" and '.' are also
                  consonants. (Actually, this is bug-compatible with the OP's original
                  example.)

                  -- Paul

                  Comment

                  • Andrew Dalke

                    #10
                    Re: split up a list by condition?

                    Reinhold Birkenfeld wrote:[color=blue][color=green][color=darkred]
                    >>> So I think: Have I overlooked a function which splits up a sequence
                    >>> into two, based on a condition? Such as
                    >>>
                    >>> vees, cons = split(wlist[::-1], lambda c: c in vocals)[/color][/color][/color]
                    [color=blue]
                    > This is clear. I actually wanted to know if there is a function which I
                    > overlooked which does that, which wouldn't be a maintenance nightmare at
                    > all.[/color]

                    Not that I know of, but if there is one it should be named
                    "bifilter", or "difilter" if you prefer Greek roots. :)


                    def bifilter(test, seq):
                    passes = []
                    fails = []
                    for term in seq:
                    if test(term):
                    passes.append(t erm)
                    else:
                    fails.append(te rm)
                    return passes, fails

                    [color=blue][color=green][color=darkred]
                    >>> bifilter("aeiou ".__contain s__, "This is a test")[/color][/color][/color]
                    (['i', 'i', 'a', 'e'], ['T', 'h', 's', ' ', 's', ' ', ' ', 't', 's', 't'])[color=blue][color=green][color=darkred]
                    >>>[/color][/color][/color]

                    Another implementation, though in this case I cheat because I
                    do the test twice, is
                    [color=blue][color=green][color=darkred]
                    >>> from itertools import ifilter, ifilterfalse, tee
                    >>> def bifilter(test, seq):[/color][/color][/color]
                    .... seq1, seq2 = tee(seq)
                    .... return ifilter(test, seq1), ifilterfalse(te st, seq2)
                    ....[color=blue][color=green][color=darkred]
                    >>> bifilter("aeiou ".__contain s__, "This is another test")[/color][/color][/color]
                    (<itertools.ifi lter object at 0x57f050>, <itertools.ifil terfalse object at 0x57f070>)[color=blue][color=green][color=darkred]
                    >>> map(list, _)[/color][/color][/color]
                    [['i', 'i', 'a', 'o', 'e', 'e'], ['T', 'h', 's', ' ', 's', ' ', 'n', 't', 'h', 'r', ' ', 't', 's', 't']][color=blue][color=green][color=darkred]
                    >>>[/color][/color][/color]


                    Andrew
                    dalke@dalkescie ntific.com

                    Comment

                    Working...