FAQ
Hi Folks,

I am quite new to python and I don't have a lot of experience with it yet.

I have two simple questions:

1. Is there a way to limit the number of times a list comprehension will
execute? E.g. I want to read from input only 5 values, so I would like
something like (the values between # # are what I want):
===================================================================================
COUNT = 0
print [ v for v in sys.stdin.readlines() *# *IF COUNT < 5* #* ] ## Increment
COUNT somewhere
===================================================================================

2.* *I would like to know another way, a more pythonic way, to write the
following:
===================================================================================
import sys

def Z(iNumber):
sum=0
while (iNumber>=5):
iNumber=iNumber/5
sum = sum + iNumber
print sum

def factorialCountZeros2():
sysStdinReadLine = sys.stdin.readline
numValues = int(sysStdinReadLine())
[ Z(int(sysStdinReadLine())) for x in xrange(numValues) ]

if __name__ == '__main__':
factorialCountZeros2()
===================================================================================
To be more specific, I would like to know about the Z function, is there a
way to rewrite that while with list comprehension?

This code is to solve the CodeChef problem:
http://www.codechef.com/problems/FCTRL/ (I am still in the easy part) and it
executed in 2.5 secs, I would like to know if there is something else I can
improve performance.

Thanks for your attention!

Regards,
Felipe.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20101110/fc408b09/attachment.html>

Search Discussions

  • Emile van Sebille at Nov 10, 2010 at 10:56 pm
    On 11/10/2010 4:36 AM Felipe Vinturini said...
    Hi Folks,

    I am quite new to python and I don't have a lot of experience with it yet.

    I have two simple questions:

    1. Is there a way to limit the number of times a list comprehension will
    execute? E.g. I want to read from input only 5 values, so I would like
    something like (the values between # # are what I want):
    ===================================================================================
    COUNT = 0
    print [ v for v in sys.stdin.readlines() *# *IF COUNT< 5* #* ] ## Increment
    COUNT somewhere
    Easiest would be print [ v for v in sys.stdin.readlines()[:5] ] but that
    still reads the entire sys.stdin (whatever it may be...)
    ===================================================================================

    2.* *I would like to know another way, a more pythonic way, to write the
    following:
    ===================================================================================
    import sys

    def Z(iNumber):
    sum=0
    while (iNumber>=5):
    iNumber=iNumber/5
    sum = sum + iNumber
    print sum

    def factorialCountZeros2():
    sysStdinReadLine = sys.stdin.readline
    numValues = int(sysStdinReadLine())
    [ Z(int(sysStdinReadLine())) for x in xrange(numValues) ]

    if __name__ == '__main__':
    factorialCountZeros2()
    ===================================================================================
    To be more specific, I would like to know about the Z function, is there a
    way to rewrite that while with list comprehension?
    Well, you could use

    def X(iNumber):
    print sum([iNumber/(5**ii) for ii in range(1,2*int(len("%s" %
    iNumber)))])

    but the range selection is rather arbitrary.

    Emile


    This code is to solve the CodeChef problem:
    http://www.codechef.com/problems/FCTRL/ (I am still in the easy part) and it
    executed in 2.5 secs, I would like to know if there is something else I can
    improve performance.

    Thanks for your attention!

    Regards,
    Felipe.
  • James Mills at Nov 11, 2010 at 12:29 am

    On Thu, Nov 11, 2010 at 8:56 AM, Emile van Sebille wrote:
    Easiest would be print [ v for v in sys.stdin.readlines()[:5] ] but that
    still reads the entire sys.stdin (whatever it may be...)
    Here's a way of doing the same thing without consuming the entire
    stream (sys.stdin):

    #!/usr/bin/env python

    import sys
    print [v for v in list(line for line in sys.stdin)[:5]]

    This uses a generator expression to read from stdin, converts this to
    a list (only getting the first 5 items).

    cheers
    James


    --
    -- James Mills
    --
    -- "Problems are solved by method"
  • MRAB at Nov 11, 2010 at 1:38 am

    On 11/11/2010 00:29, James Mills wrote:
    On Thu, Nov 11, 2010 at 8:56 AM, Emile van Sebillewrote:
    Easiest would be print [ v for v in sys.stdin.readlines()[:5] ] but that
    still reads the entire sys.stdin (whatever it may be...)
    Here's a way of doing the same thing without consuming the entire
    stream (sys.stdin):

    #!/usr/bin/env python

    import sys
    print [v for v in list(line for line in sys.stdin)[:5]]

    This uses a generator expression to read from stdin, converts this to
    a list (only getting the first 5 items).
    'list' will exhaust the input, then the slicing will return at most 5
    lines.
  • Chris Rebert at Nov 11, 2010 at 2:18 am

    On Wed, Nov 10, 2010 at 5:38 PM, MRAB wrote:
    On 11/11/2010 00:29, James Mills wrote:
    On Thu, Nov 11, 2010 at 8:56 AM, Emile van Sebille<emile at fenx.com> ?wrote:
    Easiest would be print [ v for v in sys.stdin.readlines()[:5] ] but that
    still reads the entire sys.stdin (whatever it may be...)
    Here's a way of doing the same thing without consuming the entire
    stream (sys.stdin):

    #!/usr/bin/env python

    import sys
    print [v for v in list(line for line in sys.stdin)[:5]]

    This uses a generator expression to read from stdin, converts this to
    a list (only getting the first 5 items).
    'list' will exhaust the input, then the slicing will return at most 5
    lines.
    Also, the list comprehension and generator expression are both the
    identity versions thereof, so a shorter equivalent version of the
    erroneous code would be simply:
    print list(sys.stdin)[:5]

    Cheers,
    Chris
  • James Mills at Nov 11, 2010 at 3:46 am

    On Thu, Nov 11, 2010 at 11:38 AM, MRAB wrote:
    'list' will exhaust the input, then the slicing will return at most 5
    lines.
    Hmm you're right :)

    --
    -- James Mills
    --
    -- "Problems are solved by method"
  • Steve Holden at Nov 11, 2010 at 3:02 am

    On 11/10/2010 7:29 PM, James Mills wrote:
    On Thu, Nov 11, 2010 at 8:56 AM, Emile van Sebille wrote:
    Easiest would be print [ v for v in sys.stdin.readlines()[:5] ] but that
    still reads the entire sys.stdin (whatever it may be...)
    Here's a way of doing the same thing without consuming the entire
    stream (sys.stdin):

    #!/usr/bin/env python

    import sys
    print [v for v in list(line for line in sys.stdin)[:5]]

    This uses a generator expression to read from stdin, converts this to
    a list (only getting the first 5 items).
    A generator expression slicing only accesses as many elements as it
    needs to? But surely list(line for line in sys.stdin) will be evaluated
    before the indexing is applied?

    I'd have thought that would have exhausted the input file.
    f = open("/tmp/data", "w")
    for i in 'one two three four five six seven eight nine ten'.split():
    ... f.write("%s\n" % i)
    ...
    f.close()
    f = open("/tmp/data")
    print [v for v in list(line for line in f)[:5]]
    ['one\n', 'two\n', 'three\n', 'four\n', 'five\n']
    f.next()
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    StopIteration
    >>>

    This suggests that you are mistaken about not exhausting the source.

    regards
    Steve
    --
    Steve Holden +1 571 484 6266 +1 800 494 3119
    PyCon 2011 Atlanta March 9-17 http://us.pycon.org/
    See Python Video! http://python.mirocommunity.org/
    Holden Web LLC http://www.holdenweb.com/
  • James Mills at Nov 11, 2010 at 3:48 am

    On Thu, Nov 11, 2010 at 1:02 PM, Steve Holden wrote:
    This suggests that you are mistaken about not exhausting the source.
    Yeah I was mistaken. Oh well :) I was thinking of a generator-based
    solution and got lost in the implementation!

    --
    -- James Mills
    --
    -- "Problems are solved by method"
  • James Mills at Nov 10, 2010 at 11:01 pm

    On Wed, Nov 10, 2010 at 10:36 PM, Felipe Vinturini wrote:
    1. Is there a way to limit the number of times a list comprehension will
    execute??E.g. I want to read from input only 5 values, so I would like
    something like (the values between # # are what I want):
    ===================================================================================
    COUNT = 0
    print [ v for v in sys.stdin.readlines() # IF COUNT < 5 # ] ## Increment
    COUNT somewhere
    ===================================================================================
    print [v for v in sys.stdin.readlines()[:5]]

    cheers
    James

    --
    -- James Mills
    --
    -- "Problems are solved by method"
  • Steve Holden at Nov 11, 2010 at 12:57 am

    On 11/10/2010 6:01 PM, James Mills wrote:
    On Wed, Nov 10, 2010 at 10:36 PM, Felipe Vinturini
    wrote:
    1. Is there a way to limit the number of times a list comprehension will
    execute? E.g. I want to read from input only 5 values, so I would like
    something like (the values between # # are what I want):
    ===================================================================================
    COUNT = 0
    print [ v for v in sys.stdin.readlines() # IF COUNT < 5 # ] ## Increment
    COUNT somewhere
    ===================================================================================
    print [v for v in sys.stdin.readlines()[:5]]
    how about print [sys.stdin.readline() for i in range(5)]

    At least that won't consume the whole file.

    regards
    Steve
    --
    Steve Holden +1 571 484 6266 +1 800 494 3119
    PyCon 2011 Atlanta March 9-17 http://us.pycon.org/
    See Python Video! http://python.mirocommunity.org/
    Holden Web LLC http://www.holdenweb.com/
  • Alex23 at Nov 11, 2010 at 1:01 am

    Steve Holden wrote:
    how about print [sys.stdin.readline() for i in range(5)]

    At least that won't consume the whole file.
    +1 on this approach. Clear and obvious and not reliant on any library
    modules other than sys.

    itertools, what WAS I thinking? :)
  • James Mills at Nov 11, 2010 at 3:53 am

    On Thu, Nov 11, 2010 at 11:01 AM, alex23 wrote:
    +1 on this approach. Clear and obvious and not reliant on any library
    modules other than sys.

    itertools, what WAS I thinking? :)
    maybe:

    import sys
    from itertools import islice

    print [v for v in islice((line for line in sys.stdin), 0, 5)]

    ?

    --
    -- James Mills
    --
    -- "Problems are solved by method"
  • Peter Otten at Nov 11, 2010 at 8:10 am

    James Mills wrote:
    On Thu, Nov 11, 2010 at 11:01 AM, alex23 wrote:
    +1 on this approach. Clear and obvious and not reliant on any library
    modules other than sys.

    itertools, what WAS I thinking? :)
    maybe:

    import sys
    from itertools import islice

    print [v for v in islice((line for line in sys.stdin), 0, 5)]
    (line for line in sys.stdin)

    and sys.stdin are equivalent as are

    [v for v in items]

    and list(items)

    So

    print list(islice(sys.stdin, 5))

    Peter
  • Felipe Vinturini at Nov 11, 2010 at 9:37 am

    On Thu, Nov 11, 2010 at 6:10 AM, Peter Otten wrote:

    James Mills wrote:
    On Thu, Nov 11, 2010 at 11:01 AM, alex23 wrote:
    +1 on this approach. Clear and obvious and not reliant on any library
    modules other than sys.

    itertools, what WAS I thinking? :)
    maybe:

    import sys
    from itertools import islice

    print [v for v in islice((line for line in sys.stdin), 0, 5)]
    (line for line in sys.stdin)

    and sys.stdin are equivalent as are

    [v for v in items]

    and list(items)

    So

    print list(islice(sys.stdin, 5))

    Peter
    --
    http://mail.python.org/mailman/listinfo/python-list
    Hello Folks,

    You are great! Thanks for the suggestions!

    With the values between # #, I meant I would like to limit the values
    sys.stdin.readlines() read (but I think there is no way to do it); instead
    of reading the entire input, limit it to read only 5 entries.
    I knew about readline(), but when checking it with cProfile each readline()
    needs a function call and with readlines() it is only one. I think that
    depending on input, readline() calls may have a higher cost.

    Check below:

    My test file: TestFile.txt
    =====================================================
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    =====================================================

    My test code: simpleReadLines.py
    =====================================================
    import sys
    import cProfile

    def simpleTestLimitRLS(tLimit):
    sysStdinReadLines = sys.stdin.readlines
    allValues = [ int(v) for v in sysStdinReadLines() ]
    print allValues[:tLimit]

    def simpleTestLimitRL(tLimit):
    sysStdinReadLine = sys.stdin.readline
    print [ sysStdinReadLine() for x in xrange(0,5) ]

    if __name__ == '__main__':
    cProfile.run("simpleTestLimitRL(5)")
    cProfile.run("simpleTestLimitRLS(5)")
    =====================================================

    Test result:
    =====================================================
    type TestFile.txt | python simpleReadLines.py
    ['1\n', '2\n', '3\n', '4\n', '5\n']
    8 function calls in 0.004 CPU seconds

    Ordered by: standard name

    ncalls tottime percall cumtime percall filename:lineno(function)
    1 0.000 0.000 0.004 0.004 <string>:1(<module>)
    1 0.004 0.004 0.004 0.004
    simpleReadLines.py:13(simpleTestLimitRL)
    1 0.000 0.000 0.000 0.000 {method 'disable' of
    '_lsprof.Profiler' objects}
    5 0.000 0.000 0.000 0.000 {method 'readline' of 'file'
    objects}

    [6, 7, 8, 9, 10]
    4 function calls in 0.003 CPU seconds

    Ordered by: standard name

    ncalls tottime percall cumtime percall filename:lineno(function)
    1 0.000 0.000 0.003 0.003 <string>:1(<module>)
    1 0.003 0.003 0.003 0.003
    simpleReadLines.py:8(simpleTestLimitRLS)
    1 0.000 0.000 0.000 0.000 {method 'disable' of
    '_lsprof.Profiler' objects}
    1 0.000 0.000 0.000 0.000 {method 'readlines' of 'file'
    objects}
    =====================================================

    If I change the execution order to:
    1. simpleTestLimitRLS(5)
    2. simpleTestLimitRL(5)

    Of course, python returns an error because all the input has been consumed
    by readlines().

    Again, thanks for your attention and suggestions.

    Regards,
    Felipe.
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: <http://mail.python.org/pipermail/python-list/attachments/20101111/9278b161/attachment.html>
  • James Mills at Nov 11, 2010 at 9:49 am

    On Thu, Nov 11, 2010 at 6:10 PM, Peter Otten wrote:
    (line for line in sys.stdin)

    and sys.stdin are equivalent as are

    [v for v in items]

    and list(items)

    So

    print list(islice(sys.stdin, 5))
    I was being a little verbose ... But I like your simplification :)

    cheers
    James

    --
    -- James Mills
    --
    -- "Problems are solved by method"
  • Ian at Nov 11, 2010 at 3:10 am
    On 11/10/2010 4:36 AM Felipe Vinturini said...
    2.* *I would like to know another way, a more pythonic way, to write the
    following:
    ===================================================================================
    import sys

    def Z(iNumber):
    ? ? ?sum=0
    ? ? ?while (iNumber>=5):
    ? ? ? ? ?iNumber=iNumber/5
    ? ? ? ? ?sum = sum + iNumber
    ? ? ?print sum

    def factorialCountZeros2():
    ? ? ?sysStdinReadLine = sys.stdin.readline
    ? ? ?numValues = int(sysStdinReadLine())
    ? ? ?[ Z(int(sysStdinReadLine())) for x in xrange(numValues) ]

    if __name__ == '__main__':
    ? ? ?factorialCountZeros2()
    ===================================================================================
    To be more specific, I would like to know about the Z function, is there a
    way to rewrite that while with list comprehension?
    Probably not in a way that's more efficient than what you're already
    doing. One thing you should do is to use the // operator instead
    of /. Apart from being more portable (/ no longer does integer
    division in Python 3), it's also significantly faster:

    $ python -m timeit "12 / 5"
    10000000 loops, best of 3: 0.0711 usec per loop

    $ python -m timeit "12 // 5"
    10000000 loops, best of 3: 0.028 usec per loop

    Also, don't use a list comprehension for your looping construct in
    factorialCountZeros2(). The list comprehension has to build up a list
    containing all the None objects returned by the Z() method, which
    wastes time and space. Because of that, it would be faster just to
    write it out the for loop. Besides the speed improvement, it's also
    bad style to use a list comprehension for a loop where you're only
    interested in the side effects.

    Another thing to consider is that function calls are expensive. Your
    Z() function gets called once for every line of input, which could add
    up. While it will make the code a bit less readable (CodeChef is
    definitely not the place to go if you want to learn to write *clear*
    code), you might see some improvement if you wrap that function into
    the factorialCountZeros2() function.

    Finally, one thing that really tends to help a lot in these puzzles is
    to do all your input at once and all your output at once. I/O is
    crazy expensive, but you can cut a lot of that out by minimizing the
    number of reads and writes that you have to do.

    After the first readline, you can do something like "input =
    sys.stdin.read().strip().split('\n')" to pull everything into a single
    list, then iterate over the list instead of stdin. For output, append
    all your results to a list instead of printing them immediately, then
    use '\n'.join() to generate something suitable for printing.

    Cheers,
    Ian

    P.S. CodeChef and SPOJ both have the psyco module available. If you
    just can't seem to get a problem solved in the time limit, you can
    always turn it on for a major speed boost. It's more fun to try to
    solve the problems without it, though.
  • Rantingrick at Nov 11, 2010 at 5:05 am

    On Nov 10, 4:56?pm, Emile van Sebille wrote:
    On 11/10/2010 4:36 AM Felipe Vinturini said...
    Hi Folks,
    I am quite new to python and I don't have a lot of experience with it yet.
    I have two simple questions:
    1. Is there a way to limit the number of times a list comprehension will
    execute? E.g. I want to read from input only 5 values, so I would like
    something like (the values between # # are what I want):

    Hey all you guys could be mistaken. It looks like the OP is trying to
    implement some sort of ghetto database. And he may NOT necessarily
    want the FIRST five lines of the file. He said (and i quote) "the
    values /between/ # and #". Where # and # are starting and ending of a
    range -- not necessarily the starting of the input file! However we
    really need the OP to clear up these questions!
  • James Mills at Nov 11, 2010 at 5:18 am

    On Thu, Nov 11, 2010 at 3:05 PM, rantingrick wrote:
    Hey all you guys could be mistaken. It looks like the OP is trying to
    implement some sort of ghetto database. And he may NOT necessarily
    want the FIRST five lines of the file. He said (and i quote) "the
    values /between/ # and #". Where # and # are starting and ending of a
    range -- not necessarily the starting of the input file! However we
    really need the OP to clear up these questions!
    Valid point Rick. And yes my earlier post was very wrong :/

    My follow-up (after realizing my mistake) might be better (using islice).

    cheers
    James

    --
    -- James Mills
    --
    -- "Problems are solved by method"
  • R0g at Nov 11, 2010 at 6:04 am

    On 10/11/10 22:56, Emile van Sebille wrote:
    On 11/10/2010 4:36 AM Felipe Vinturini said...
    Hi Folks,

    I am quite new to python and I don't have a lot of experience with it
    yet.

    I have two simple questions:

    1. Is there a way to limit the number of times a list comprehension will
    execute? E.g. I want to read from input only 5 values, so I would like
    something like (the values between # # are what I want):
    ===================================================================================

    COUNT = 0
    print [ v for v in sys.stdin.readlines() *# *IF COUNT< 5* #* ] ##
    Increment
    COUNT somewhere
    Easiest would be print [ v for v in sys.stdin.readlines()[:5] ] but that
    still reads the entire sys.stdin (whatever it may be...)

    Use readline() + a counter instead...

    print [sys.stdin.readline() for x in xrange(0,5)]

    Roger

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedNov 10, '10 at 12:36p
activeNov 11, '10 at 9:49a
posts19
users11
websitepython.org

People

Translate

site design / logo © 2023 Grokbase