Python how to loop multiple variables and different steps parallel? - python

How to loop multiple variables and different steps parallel?
Like, in c++, for(int i=0, j=n-1; i<n && j>=0; i++, j--).

You can use the built-in function zip() to iterate multiple iterables in parallel:
for i,j in zip(range(n), range(n-1, -1, -1)):
print(i, j)
Possible output:
0 9
1 8
2 7
3 6
4 5
5 4
6 3
7 2
8 1
9 0
zip() will stop iteration once the first iterator is exhausted. When you want to continue until the last is done, providing fill values for the others, you can use itertools.zip_longest().
For reference:
https://docs.python.org/3/library/functions.html#zip
https://docs.python.org/3/library/itertools.html#itertools.zip_longest

In Python, for loops are usually iterated over a sequence (such as but not limited to: a list, numpy array, a range, enumerated type, dict items etc).
The below implementation is a zip'd form of two range objects:
for i, j in zip(range(0, n, 1), range(n-1, -1, -1)):
print(i, j)
The limitation in this approach is that the two sequences (one over i and one over j must be of the same length.
However, if say i iterates over n elements and j over m elements, then the number of times the loop will be executed will be min(i, j), i.e., the execution exits the loop as soon as one of the sequences is completed.

Related

How to create list and initialize only some of it's values in Python (in comparison to C++)

I need to create an List of size N and then initialize only N-1th and N-2th elements only. Which means if the size of the list is 5 then it should only contain elements in 3rd and 4th position.
i know how to do it in C++ but is there any way to implement it in Python?
for example: In C++
int *n = new int[5];
n[3] = 20
n[4] = 10
//and if we print the output it will show some garbage values in index 0, 1, 2 and will print 20 10 which is the values we initailized
How can i do it in python? or anything similar to this!
In python, list must be initialized with values.
Closest thing you can do:
N = 5
lst = [0] * (N-2) + [20, 10]
This:
Fills the N-2 elements of a list with default value 0
Sets the value for the last two elements
Concatenates the zeros and last two elements sub-lists of stages 1 & 2
In python,
array=[]
length=5
for i in range(length):
array.append(0)
array[3]=20
array[4]=10
Edit: As pointed out by kabanus, a more efficient way to do this would be-
array=[0]*length
Instead of the for loop.

Nested loop not printing the first element but going to 2nd element?

I have a very simple piece of code but it's driving me nuts to understand the logic.
for a in range(6):
print("\t\t")
for j in range(a):
print(a, end=" ")
The output is:
1
2 2
3 3 3
4 4 4 4
5 5 5 5 5
the first value to be printed is supposed to be 0 since the range(6) starts from 0 and a and j wrapped in for loops both are supposedly getting 0 as first element but it starts from 1 instead.
That comes, because the for loop in range 0 will not be executed. You can not execute something if that has to go 0 times. To make it run as you would like to be, you would have to write following code:
for a in range(6):
print("\t\t")
for j in range(a + 1):
print(a, end=" ")
The value of a is the number of iterations of the inner loop. (Note that the question should have the j loop indented, so that it is inside the a loop, in order to get the output shown.)
On the first iteration, a is 0, and then range(0) will give an empty sequence, which give zero iterations when iterating over it. (Specifically a StopIteration will occur the first time a value is fetched.)
On the next iteration of the outer loop, there will be one j value when iterating, and so forth.
So 0 is printed 0 times (i.e. not at all), then 1 is printed once, 2 is printed twice, ... , 5 is printed 5 times.
You are not using the values of j at all, but they will be:
when a is 0: no iterations
when a is 1: j is 0 only
when a is 2: j is 0, 1
... etc, up to ...
when a is 6: j is 0, 1, 2, 3, 4, 5
Note that in fact it is conventional to use a variable name _ for a loop variable whose value you do not use (at least assuming that it not inside a loop already using _). If you adhere to this convention (i.e. use _ instead of j) and also fix the indentation, then your code might look like:
for a in range(6):
print("\t\t")
for _ in range(a):
print(a, end=" ")

Implementing sigma in python/R with fewer loops

I want to implement the following function in python:
I will write the code using 2-loops:
for i in range(5):
for j in range(5):
sum += f(i, j)
But the issue is that I have 20 such sigmas, so I will have to write 20 nested for loops. It makes the code unreadable. In my case, all i and j variables take same range (0 to 4). Is there some better of coding it?
You can use itertools.product to get cartesian product (of indexes for your cases):
>>> import itertools
>>> for i, j, k in itertools.product(range(1, 3), repeat=3):
... print(i, j, k)
...
1 1 1
1 1 2
1 2 1
1 2 2
2 1 1
2 1 2
2 2 1
2 2 2
import itertools
total = 0
for indexes in itertools.product(range(5), repeat=20):
total += f(*indexes)
You should use range(1,6) instead of range(5) to mean 1 to 5. (unless you meant indexes)
Do not use sum as a variable name, it shadows builtin function sum.
Create Arrays by using Numpy .
import numpy as np
i = np.asarray([i for i in range(5)])
j = np.asarray([i for i in range(5)])
res = np.sum(f(i,j))
so you can avoide all loops. Important to note is that the function f needs to be able to work with array (a so called ufunc). If your f is more complicated and i doesnt allow arrays you can use numpys vectorize functions. Not as fast as a ufunc but better that nested loops :
from numpy import vectorize
f_vec = vectorize(f)
If you want to stay with plain python because you don't want arrays but lists or the types don't match for an array, there is always list comprehension which speeds up the loop. Say I and J are the iterable for i and j respectively then:
ij = [f(i,j) for i in I for j in J ]
res = sum(ij)

Prime numbers in a given range using Sieve of Eratosthenes

I am trying to print prime numbers less than 'n'.The code is below:
def prime_numbers(n):
A=[1 for i in range(n+1)]
for i in range(2,int(sqrt(n))):
if A[i]==1:
for j in range(i*2,n,i):
A[j]=0
for i in range(n):
if A[i]:
print(i)
Output for
prime_numbers(10)
is
0
1
2
3
5
7
9
The program correctly prints for 100. What changes do I need to make?
The end point in a range() is not included. Since sqrt(10) is 3.1623, your range() loops to 2 and no further, and the multiples of 3 are not removed from your list. Your code works for 100, because it doesn't matter if you test for multiples 10 (those are already covered by 2 and 5).
The same issue applies to your other loops; if you want to include n itself as a candidate prime number you should also include it in the other ranges.
Note that you also want to ignore 0 and 1, those are not primes. You could add A[0] = A[1] = False at the top to make sure your last loop doesn't include those, or start your last loop at 2 rather than 0.
You want to add one to the floored square root to make sure it is tested for:
for i in range(2, int(sqrt(n)) + 1):
I'd use booleans rather than 0 and 1, by the way, just for clarity (there is not much of a performance or memory footprint difference here):
def prime_numbers(n):
sieve = [True] * (n + 1) # create a list n elements long
for i in range(2, int(sqrt(n)) + 1):
if sieve[i]:
for j in range(i * 2, n + 1, i):
sieve[j] = False
for i in range(2, n + 1):
if sieve[i]:
print(i)
I used [..] * (n + 1) to create a list of n items (plus 0); this produces a list with n shallow copies of the contents of the left operand. That's faster than a list comprehension, and the shared references are fine since True is a singleton in Python.
Demo:
>>> prime_numbers(31)
2
3
5
7
11
13
17
19
23
29
31
Note that 31 is included there; your code would have resulted in incorrect output as you'd have left in all the multiples of 5.

Converting C style for loop to python

How do you convert a c-style for loop into python?
for (int i = m; i >= lowest; i--)
The best that I came up with was:
i = mid
for i in range(i, low,-1):
for i in range(m, low - 1, -1):
Keep in mind range is exclusive of the stop parameter.
range(...)
range(stop) -> list of integers
range(start, stop[, step]) -> list of integers
The difference between this code and the C code is that in Python 2, a list is being constructed in memory by range so for very huge ranges this could be a problem. Replacing range with xrange would not build a list in memory and make the code practically the same. In Python 3 this issue no longer exists.
m from where the loop start.
l where the loop stop, and range exclude last item so l-1 and
-1 for reverse array.
for i in range(m, l-1, -1):
m = 20
low = 10
for i in range(m, low - 1, -1):
print i
This will count down as expected:
20
19
18
17
16
15
14
13
12
11
10
range takes three parameters, a start, a stop and the increment between each step.
Where possible, the Python idiom is to loop over the items directly, not to count through them. Therefore an idiomatic way to count down would be for item in reversed(list): print item or to take a reversed slice >>> someList[m:lowest-1:-1]
If you are looping over items and also need a counter, Python has enumerate() to generate counting index numbers while looping. for index, value in enumerate(someList):
It's not always possible to do this, sometimes you are counting and not going over any other data except the numbers, and range() is fine - as the other answers suggest. But when you have a for (int i=... loop, see if you can change it to act directly on the data. Writing "C in Python" is no fun for anyone.

Categories

Resources