How to count by twos with Python's 'range' - python

So imagine I want to go over a loop from 0 to 100, but skipping the odd numbers (so going "two by two").
for x in range(0,100):
if x%2 == 0:
print x
This fixes it. But imagine I want to do so jumping two numbers? And what about three? Isn't there a way?

Use the step argument (the last, optional):
for x in range(0, 100, 2):
print(x)
Note that if you actually want to keep the odd numbers, it becomes:
for x in range(1, 100, 2):
print(x)
Range is a very powerful feature.

(Applicable to Python <= 2.7.x only)
In some cases, if you don't want to allocate the memory to a list then you can simply use the xrange() function instead of the range() function. It will also produce the same results, but its implementation is a bit faster.
for x in xrange(0,100,2):
print x, #For printing in a line
>>> 0, 2, 4, ...., 98
Python 3 actually made range behave like xrange, which doesn't exist anymore.

for i in range(0, 100, 2):
print i
If you are using an IDE, it tells you syntax:
min, max, step(optional)

Related

Python list with zeros and numbers repeating

My intent is to generate a generic empty list and then to append it with a numeric sequence such that it gives zeros but at the third place it gives 3 and then its multiples, that is a[(0,0,3,0,0,6,0,0,9)] and it needs to have 100 values inside.
I first set the list and then I use the 'for' loop in a range(0,100) and I am sure I need to use % in ways such that whenever my sequence going 1 to 100 is perfectly divisible by 3 it gives back 3 (and not 0) but then it keeps evolving in 6,9,12.. How do I do?
for i in range(0,100):
if i%3==0:
return 0
else
return 3
Of course this is completely wrong but i am new to programming in general. Thanks in advance.
you could try this:
for i in range(0, 100, 3):
list[i]=i
You just change the "step" of the range function, so the index i will represent also the value passed in the list, it should work properly.
#Mark's comment is very relevant and makes good use of the modulo and list comprehension properties in a very simple way. Moreover, its code easily adapts to any value.
However the modulo operator is quite slow so here are other ways to achieve the same result.
Method 1
We can make a range from 3 to 101 with a step of 3, and add [0, 0, i] to each step. Since there will be missing zeros at the end of the list, we must add as many as the rest of the division of 100 by 3.
data = [num for i in range(3, 101, 3) for num in [0, 0, i]] + [0] * 1
Method 2
With the same idea, we can use .extend() to add two 0s before each term.
data = []
for i in range(3, 101, 3):
data.extend([0, 0, i])
data.append(0)
Method 3
The simplest idea, we create a list of 100 zeros, and then we modify the value every 3 terms.
data = [0] * 100
for i in range(2, 101, 3):
data[i] = i + 1
Comparison
Using timeit, here is a comparison of the speed of each algorithm, the comparison is based on 10000 repetitions.
import timeit
print(timeit.timeit("data = [0 if n % 3 else n for n in range(1, 101)]"))
print(timeit.timeit("data = [num for i in range(3, 101, 3) for num in [0, 0, i]] + [0] * 1"))
print(timeit.timeit("""
data = []
for i in range(3, 101, 3):
data.extend([0, 0, i])
data.append(0)
"""))
print(timeit.timeit("""
data = [0] * 100
for i in range(2, 101, 3):
data[i] = i + 1
"""))
Output:
4.137781305000317
3.8176420609997876
2.4403464719998738
1.4861199529996156
The last algorithm is thus the fastest, almost 3 times faster than using modulus.
A function stops running, when it encounters a return. So in your code, you only ever execute the loop once.
But, what if we could change that? Do you know what a generator is? Have a look at this:
def multiples_of_three_or_zero():
for i in range(0,100):
if i%3==0:
yield 0
else
yield 3
That's a generator. yield doesn't end the execution, but rather suspends it. You use it like this:
for i in multiples_of_three_or_zero():
print(i)
Or, if you really want all the elements in a list, just make a list from it:
list(multiples_of_three_or_zero())
Ok I practiced a little bit and I found this solution which best suits my needs (it was for a take-home exercise)
A=[]
for a in range (1,101):
if a%3==0:
A.append(a)
else:
A.append(0)
print(A)
thanks you all!

in Python, range(1, 100, *10) doesn't work?

I have a problem with range() or the for loop.
in C++, the for loop can be used like this:
for(int i=1;i<=100;i*=10){
//lala
}
My Python script that causes the error looks like this:
li = [x for x in range(100, 0, /10)]
print(li)
I hope to get li = [100, 10, 1]
How can I achieve this without the use of li.append ( 100, 10, 1 )?
You can't use range for this. The third argument for range is a fixed step used to increment the value: it can't be used to multiply or divide the previous value.
Instead, use a while loop:
i = 1
while i < 100:
...
i *= 10 # or i /= 10 depending on what you want.
If you really want to use a list comprehension, you can do as suggested by Albin Paul:
li = [10**x for x in range(3) ] # [1, 10, 100]
li = [10**x for x in range(2, -1, -1) # [100, 10, 1]
You can simply use a generator expression, like
for i in (10 ** x for x in range(2, -1, -1)):
print(i)
# 100
# 10
# 1
Or, if you want your "power range" to be a reusable function, you can create your own, i.e.
def powrange(*args, base=10):
for i in range(*args):
yield base ** i
for i in powrange(2, -1, -1, base=10):
print(i)
# 100
# 10
# 1
The built-in range is not meant to be used this way. It takes three arguments: range(start, stop, step) and goes from start to stop with a constant stepsize.
If you want to use a single function, you could use numpy's logspace
It looks like this:
import numpy
li = numpy.logspace(0, 2, base=10, dtype = int)
# li is [1, 10, 100]
# goes from base^0 to base^2, so from 1 to 100
If you don't want to rely on numpy, the solution with a while loop seems very pythonic to me.
Benchmark time :D
A comment pointed out that this solution might be:
non obvious
slow
The first point is a matter of taste, but I disagree on performance:
reps = 100000
list_elems = 100
start = time.perf_counter()
for i in range(reps):
np.logspace(0, list_elems, base=2, dtype=int)
end = time.perf_counter()
numpy_time = end - start
start = time.perf_counter()
for i in range(reps):
[2**x for x in range(list_elems)]
end = time.perf_counter()
python_time = end - start
# reps = 100000
# list_elems = 100
# numpy took 1.70, python took 2.86
# reps = 100000
# list_elems = 10
# numpy took 1.65, python took 0.242
Of course, this depends a lot on the number of list elements that you want to produce. Numpy introduces overhead but scales better. So for shorter lists, python wins.
To change make a log(n) time complexity loop you need the log function or use while loops to do the job
In [10]: import math
In [9]: [10**x for x in range( 0,int(math.log10(1000)))]
Out[9]: [1, 10, 100]
I still think while loops are the way to go
The arguments for range are: start, stop and step, where the step is int.
Maybe you want to see the result as this:
li = [10**x for x in range(0, 3, 1)]
print(li)
[1, 10, 100]
Overall take a look at a nice learning course, for example, "Automate the Boring Stuff with Python":
Here is the video right about loops
And here is the whole
course (available online for free)
When you use the for loop as
with x in range(start,stop,step)
The way it takes place is that first
Edit: The first part is explanation why it won't work
You get a list generated by the range function(Not since python3 though), now it only returns a function range and its current state, this can be of float or int, so using /10 as step there will do nothing other than Invalid syntax, because range only accepts integers.
Only after this does x gets initialized and starts taking values present in the dictionary in an indexed way.
You can however use
for y in range(2,-1,-1):
x = (10**y)
Welcome to python and happy coding.
Thanks to #GPhilo for pointing out the errors.

for loop list incrementation

In order to find multiples of 3 under 1000, I used this method:
a=[]
import itertools
for x in itertools.count():
while x<1000:
if x%3==0:
a.append[x]
print(a)
I'm a beginner, please help me find the error.
Why not simply
a = list(range(0, 1000, 3))
or even
a = range(0, 1000, 3)
in Python 2?
Are you coding in Python 3 ?
You are missing indentation mostly and usage of function depends on the version of Python you are using and also there are different solutions to how you can handle the iterations , which may differ to your style. I also want to point out that append method needs parentheses instead of brackets.
However i tried not to modify your code much.
You can check it on the online editor below.
https://repl.it/#Umbreon1/SpiffyAshamedPdf
import itertools
a=[]
upperLimit=1000
for x in itertools.islice(itertools.count(0),upperLimit + 1):
if x%3 == 0:
a.append(x)
print(a)

Iterate a huge list of integers which grow exponentially, where the exponent is 1.5

I need to iterate a list of integers:
2, 3, 4, 6, 9, 13, 19, 28, 42, ...
So the general rule is list[i+1] = list[i]*3/2.
The list should end at or right before 10^34.
This means that the last element is a number between 10^34*2/3 and 10^34.
I obviously cannot have this list preallocated in memory, so something like:
list = [2]
while True:
next = list[-1]*3/2
if next > 10**34:
break
list.append(next)
Is out of the question.
I can of course simply use the above in order to iterate these integers without having them stored in a list or generated by an iterator of some sort.
But the problem is that I have nested loops, like so:
for i in xrange(...):
for j in xrange(...):
for m in xrange(...):
for n in xrange(...):
So breaking this into several while loops would make the code pretty horrible.
Ideally, I would like to have some sort of xrange which generates this list of numbers "on the fly" (as xranges normally do).
As I mentioned in my comment, the list won't actually be very long. You could therefore initialise it as:
[int(2 * (1.5 ** n)) for n in range(int(math.log(10 ** 34, 1.5) - 1))]
However, this is actually slightly different to the example you gave, wherein you round to integer before generating the next number. In this case, you would have to do something iterative instead (as far as I can tell):
i = 2
lst = []
while i < 10 ** 34:
lst.append(i)
i = int(i * 1.5)
This might be what you're looking for:
lst = [2*1.5**i for i in range(0,192)]
The last term would be 2*1.5^191.
If you want them all to be integers you could say use the int() cast.
But you should note that the time/memory to do this will probably be similar to what you were doing in your example code. They are both doing similar things in the end.
If you want them all to be integers throughout the process:
i = 2
lst = [2]
while i < 10**34:
lst.append(int(i*=1.5))
Again, this will only save a trace amount of memory/time.

Python memory error for integer and math

When I run my code below I get Memory Error
import math
X = 600851475143
halfX = math.trunc(int(X / 2))
countFactors = 0
for i in range(halfX):
if i >0 and X % i:
countFactors += 1
print countFactors
I understand because of math calcs here but I do not know how to correct it.
I'm going to guess you're using Python 2.7 (or 2.x, at any rate).
If that's the case, you should use xrange instead of range.
In python 3.x, range creates an iterator that only uses a few bytes of memory regardless of how large it is. In python 2.x, range always creates a list containing numbers counting up (or down) over the specified range. Calling range(some_large_number) can cause you to run out of memory in 2.x.
Therefore, Python 2.x has xrange which creates an iterator identical to range in 3.x.
Also, you can simplify your math somewhat. For example:
x = 600851475143
half_x = x // 2
count_factors = 0
for i in xrange(half_x):
if i > 0 and x % i == 0:
count_factors += 1
print count_factors
However, there are much more efficient ways to do this.
As a simple example, if the number is divisible by two, you can iterative over every other number, cutting the number of tests in half. Similarly, if it's divisible by 3, 5, etc.
I'll leave it to you to figure out the generalization. It's a fun problem :)

Categories