At 08:20 AM 8/23/2007, Kent Johnson wrote:
>Dick Moores wrote:
>>At 07:34 PM 8/22/2007, Kent Johnson wrote:
>>>FWIW here is my fastest solution:
>>>
>>>01 from itertools import chain
>>>02 def compute():
>>>03 str_=str; int_=int; slice_=slice(None, None, -1)
>>>04 for x in chain(xrange(1, 1000001, 10), xrange(2, 1000001, 10),
>>>05 xrange(3, 1000001, 10), xrange(4, 1000001, 10), xrange(5, 1000001, 10),
>>>06 xrange(6, 1000001, 10), xrange(7, 1000001, 10), xrange(8, 1000001, 10),
>>>07 xrange(9, 1000001, 10)):
>>>08 rev = int_(str_(x)[slice_])
>>>09 if rev>=x: continue
>>>10 if not x % rev:
>>>11 print x,
>>>12 compute()
>
>>And at first I thought your use of str_, int_, and slice_ were
>>pretty weird; instead of your line 08, why not just use the straightforward
>>rev = int(str(x)[::-1])
>>but on upon testing I see they all make their respective
>>contributions to speed.
>>But I don't understand why. Why is your line 08 faster than "rev =
>>int(str(x)[::-1])"?
>
>Two reasons. First, looking up a name that is local to a function is
>faster than looking up a global name. To find the value of 'str',
>the interpreter has to look at the module namespace, then the
>built-in namespace. These are each dictionary lookups. Local values
>are stored in an array and accessed by offset so it is much faster.
Wow, what DON'T you understand?
Please explain "accessed by offset".
>Second, the slice notation [::-1] actually creates a slice object
>and passes that to the __getitem__() method of the object being
>sliced. The slice is created each time through the loop. My code
>explicitly creates and caches the slice object so it can be reused each time.
>>BTW I also thought that
>>for x in chain(xrange(1, 1000001, 10), xrange(2, 1000001, 10),
>>xrange(3, 1000001, 10), xrange(4, 1000001, 10), xrange(5, 1000001, 10),
>>xrange(6, 1000001, 10), xrange(7, 1000001, 10), xrange(8, 1000001, 10),
>>xrange(9, 1000001, 10)):
>> pass
>>MUST take longer than
>>for x in xrange(1000000):
>> pass
>>because there appears to be so much more going on, but their
>>timings are essentially identical.
>
>Well for one thing it is looping 9/10 of the number of iterations.
This time I added "xrange(10, end, 10)" and did the timing using the
template in the timeit module:
template = """
def inner(_it, _timer):
_t0 = _timer()
from itertools import chain
end = 1000000
for _i in _it:
for x in chain(xrange(1, end, 10), xrange(2, end, 10),
xrange(3, end, 10), xrange(4, end, 10), xrange(5, end, 10),
xrange(6, end, 10), xrange(7, end, 10), xrange(8, end, 10),
xrange(9, end, 10), xrange(10, end, 10)):
pass
_t1 = _timer()
return _t1 - _t0
"""
This gets always close to 71 msec per loop.
template = """
def inner(_it, _timer):
_t0 = _timer()
end = 1000000
for _i in _it:
for x in xrange(end):
pass
_t1 = _timer()
return _t1 - _t0
"""
This gets always close to 84 msec per loop.
So they're not the same! And yours is the faster one! Because
itertools.chain() is written in C, I suppose.
> Also, chain() doesn't have to do much, it just forwards the values
> returned by the underlying iterators to the caller, and all the
> itertools methods are written in C to be fast. If you read
> comp.lang.python you will often see creative uses of itertools in
> optimizations.
I just did a search on "itertools" in the comp.lang.python group at
Google Groups, and got 1,940 hits. <http://tinyurl.com/3a2abz>. That
should keep me busy!
Dick
======================================
Bagdad Weather
<http://weather.yahoo.com/forecast/IZXX0008_f.html>
_______________________________________________
Tutor maillist - [email protected]
http://mail.python.org/mailman/listinfo/tutor