is there a better way?

drrngrvy drrngrvy at gmail.com
Sun Feb 12 15:48:48 EST 2006


Bruno Desthuilliers wrote:
> markscala at gmail.com a écrit :
> > Problem:
> >
> > You have a list of unknown length,
>
> This doesn't exist in Python:
>    len(alist)
>
> > such as this: list > [X,X,X,O,O,O,O].  You want to extract all and only the X's.
>
> braindead solution - relying on zeros being zeros or any other False value:
> all_xxx
> >  You know
> > the X's are all up front and you know that the item after the last X is
> > an O, or that the list ends with an X.  There are never O's between
> > X's.
> >
>
> Then it *may* be possible to optimize - but code will break as soon as
> this rule change. So is there a real need for optimisation ? (hint: dont
> guess, profile)
>
>
> FWIW, I've collected all suggestions here (and perhaps some others) and
> hacked a Q&D benchmark. Usage is:
>
> python test_lists.py [repeat [list_size [xcount]]
>
> where:
> * repeat is the number of iteration, default to 1000
> * list_size is the size of the list, default to 100
> * xcount is the number or non-zero values in the list, default is random
>
> I've run it a few times, and it seems that in most cases,
>   *  the bisect-like approach (Alex Martelli / Karl Friedrich Bolz) is
> the winner
>   * the while/pop approach of the OP (slightly rewritten...) is really wrong
>
> FWIW, one of the dummiest possible approach IMHO
> (ie filter(None, alist)) behaves quite correctly wrt some other
> 'optimized' approachs - and is still safe if the rules about the
> composition of the list changes... Could it be that no optimization is
> sometime the best optimisation ?-)
>
>
> # test_lists.py
> from itertools import takewhile
> from timeit import Timer
> from random import randint
>
> def get_list(size, xcount=None):
>      if xcount is None:
>          xcount      else:
>          assert xcount <     zcount      return [1] * xcount + [0] * zcount
>
> def with_while(alist):
>      res      while alist and alist[0]:
>          res.append(alist.pop(0))
>      return res
>
> def with_for(alist):
>      res      for x in alist:
>          if not x: break
>          res.append(x)
>      return res
>
> def with_filter(alist):
>      return filter(None, alist)
>
> def with_comprehension(alist):
>      return [x for x in alist if x]
>
> def with_takewhile(alist):
>      return list(takewhile(lambda x: x!=0, alist))
>
> def with_slice_try(alist):
>      try:
>          return alist[:alist.index(0)]
>      except ValueError:
>          return alist[:]
>
> def with_slice_safe(alist):
>      alist.append(0)
>      return alist[:alist.index(0)]
>
> def with_delslice_safe(alist):
>      alist.append(0)
>      del alist[alist.index(0):]
>      return alist
>
> def with_sect(alist):
>      low      high      while low < high:
>          mid          if alist[mid] = 0:
>              high          else:
>              low      return alist[:low]
>
> _candidates                 if n.startswith('with_') and callable(o)]
>
> def run_test(repeat00, list_size='100', xcount='None'):
>      global _candidate
>
>      print """
> params :
>   * repeat : %s
>   * list_size : %s
>   * xcounts : %s
> """  % (repeat, list_size, xcount)
>      results      for n in _candidates:
>          stm, stp                      'from __main__ import %s, get_list' % n)
>          results[n]
>      sorted_results                                for n, time in results.items()])
>      for _, result in sorted_results:
>          print "%s : %s" % result
>
>
> def main(args):
>      try:
>          repeat      except:
>          repeat      try:
>          list_size      except:
>          list_size      try:
>          xcount      except:
>          xcount
>      run_test(repeat, list_size, xcount)
>
> if __name__ = '__main__':
>      import sys
>      main(sys.argv[1:])
> 
> 
> HTH




More information about the Python-list mailing list