I need to change the condition so that the loop is finite and list_ contains following values:
1 2 4 8 16 32 64
This is what I have in python, and I am struggling to understand what exactly needs to be changed and why.
list_ = []
i = 0
while i >= 0: # change the condition
list_.append(2 ** i)
i += 1
print(list_)
I suggest to use a for-loop instead of a while loop.
list_ = []
for i in range(7):
list_.append(2 ** i)
print(list_)
If you want to be very pythonic, then you can use a list comprehension:
list_ = [2 ** i for i in range(7)]
With a while a breaking condition is required (this implementation is to highlight the break)
out = []
i = 0
while True:
if i > 6:
break
out.append(2**i)
i += 1
print(out)
or with a list comprehension
print([2**i for i in range(6+1)])
Looks like you'll only need to switch the while condition in the loop. Rather than have a lower bound, you'll need to update with an upper bound - basically a "loop until" condition.
list_ = []
i = 0
while i <= 6: # change the condition
list_.append(2 ** i)
i += 1
print(list_). # [1, 2, 4, 8, 16, 32, 64]
But you can simplify this even further, with the help of a list comprehension. This is just a fancy (and bit more efficient) way of writing a for loop in python. Its more efficient because it doesn't need to call list.append within each loop iteration.
>>> [2 ** i for i in range(7)]
[1, 2, 4, 8, 16, 32, 64]
You could use while i <= 6: so that you while loop counts up to i=6.
However, I would recommend to use a for-loop with range(6) as a condition. So that your loop looks like the following:
for i in range(7):
…
This is just an alternative way, where i also counts up to the value of 6. using a for-loop would be good practice, as it saves you to declare i previously.
Related
Let's say I want to get the the number of jumps of each consecutive 1's in a binary string of say, 169, which is 10101001.
The answer then it'd be 3, 2, 2 because when the algorithm starts at the most right digit of the binary number needs to move thrice to the left to reach the next 1, twice to get the next 1 and so on.
So the algorithm should have a counter that starts at 0, increments in one while finds 0's and reset each time it reaches a 1.
I need the output to be in form of a list using list comprehesion.
This is what I got so far:
number = 169
list = []
c = 1
for i in bin(number>>1)[:1:-1]:
if i == '1':
list.append(c)
c = 0
c += 1
The algorithm indeed works but the idea is to transform it into one line code using list compreshesion. I think that there should be one way to do it using enumerate().
Just like:
n = 169
list = [i for i, c in enumerate(bin(number>>1)[:1:-1], 1) if c == '1']
The problem is that the output will be [3, 5, 7] instead of [3, 2, 2] because the i (index variable) didn't reset.
I'm looking for an asnwer that isn't just straight list[a+1] - list[a] but more elegant and efficient solution.
Here's a one-liner for this problem that's most probably not readable.
s = "10101001"
result = [p - q for p, q in zip([index for index, a in enumerate(s[::-1]) if a == "1"][1:], [index for index, b in enumerate(s[::-1]) if b == "1"][:s.count("1")-1])]
You can use groupby here:
bs = "10101001"
result = [
sum(1 for _ in g) + 1 # this can also be something like len(list(g)) + 1
for k, g in groupby(reversed(bs))
if k == "0"
]
You cannot really do this easily with just the list comprehension, because what you want cannot be expressed with just mapping/filtering (in any straightforward way I can think of), but once you have a grouping iterator, it simply becomes suming the length of "0" runs.
you can easily do this with a regex pattern
import re
out = [len(i) for i in re.findall("0*1", num)]
output
print(out)
>>> [3, 2, 2]
>>> k = 8
>>> for i in range(k):
print i
k -= 3
print k
Above the is the code which prints numbers from 0-7 if I use just print i in the for loop.
I want to understand the above code how it is working, and is there any way we can update the value of variable used in range(variable) so it iterates differently.
Also why it always iterates up to the initial k value, why the value doesn't updated.
I know it's a silly question, but all ideas and comments are welcome.
You can't change the range after it's been generated. In Python 2, range(k) will make a list of integers from 0 to k, like this: [0, 1, 2, 3, 4, 5, 6, 7]. Changing k after the list has been made will do nothing.
If you want to change the number to iterate to, you could use a while loop, like this:
k = 8
i = 0
while i < k:
print i
k -= 3
i += 1
The expression range(k) is evaluated just once, not on every iteration. You can't set k and expect the range(k) result to change, no. From the for statement documentation:
The expression list is evaluated once; it should yield an iterable object.
You can use a while loop instead:
i = 0
k = 8
while i < k:
print i
i += 1
k -= 3
A while loop does re-evaluate the test each iteration. Referencing the while statement documentation:
This repeatedly tests the expression and, if it is true, executes the first suite
If you do want to change k and affect the loop you need to make sure you are iterating over mutable object. For example:
k = list(range(8))
for i in k:
print(i)
k.pop()
k.pop()
k.pop()
print(k)
Or alternatively:
k = list(range(8))
for i in k:
print(i)
k[:] = k[:-3]
print(k)
Both will result with
0
[0, 1, 2, 3, 4]
1
[0, 1]
you could do it like this ,I think, but I dont know if this is what you want.
def to_infinity():
index = 0
while True:
yield index
index += 1
for i in to_infinity():
print(i)
I am very new to programming, so please bear with me...I have been learning Python and I just did an assessment that involved looping through a list using your current value as the next index value to go to while looping. This is roughly what the question was:
You have a zero-indexed array length N of positive and negative integers. Write a function that loops through the list, creates a new list, and returns the length of the new list. While looping through the list, you use your current value as the next index value to go to. It stops looping when A[i] = -1
For example:
A[0] = 1
A[1] = 4
A[2] = -1
A[3] = 3
A[4] = 2
This would create:
newlist = [1, 4, 2, -1]
len(newlist) = 4
It was timed and I was not able to finish, but this is what I came up with. Any criticism is appreciated. Like I said I am new and trying to learn. In the meantime, I will keep looking. Thanks in advance!
def sol(A):
i = 0
newlist = []
for A[i] in range(len(A)):
e = A[i]
newlist.append(e)
i == e
if A[i] == -1:
return len(newlist)
This might be the easiest way to do it if your looking for the least lines of code to write.
A = [1,4,-1,3,2]
B = []
n = 0
while A[n] != -1:
B.append(A[n])
n = A[n]
B.append(-1)
print(len(B))
First of all, note that for A[i] in range(len(A)) is a pattern you certainly want to avoid, as it is an obscure construct that will modify the list A by storing increasing integers into A[i]. To loop over elements of A, use for val in A. To loop over indices into A, use for ind in xrange(len(A)).
The for loop, normally the preferred Python looping construct, is not the right tool for this problem because the problem requires iterating over the sequence in an unpredictable order mandated by the contents of the sequence. For this, you need to use the more general while loop and manage the list index yourself. Here is an example:
def extract(l):
newlist = []
ind = 0
while l[ind] != -1:
newlist.append(l[ind])
ind = l[ind]
newlist.append(-1) # the problem requires the trailing -1
print newlist # for debugging
return len(newlist)
>>> extract([1, 4, -1, 3, 2])
[1, 4, 2, -1]
4
Note that collecting the values into the new list doesn't really make sense in any kind of real-world scenario because the list is not visible outside the function in any way. A more sensible implementation would simply increment a counter in each loop pass and return the value of the counter. But since the problem explicitly requests maintaining the list, code like the above will have to do.
It's simpler to just use a while loop:
data = [1,4,-1,3,2]
ls = []
i = 0
steps = 0
while data[i] != -1:
ls.append(data[i])
i = data[i]
steps += 1
assert steps < len(data), "Infinite loop detected"
ls.append(-1)
print ls, len(ls)
How to increment the outer iterator from the inner loop?
To be more precise:
for i in range(0,6):
print i
for j in range(0,5):
i = i+2
I am getting
0
1
2
3
4
5
, but I want 0,2,4
Above is the simpilfied idea what I want to acheive.
Here is my Java code:
str1="ababa"
str2="aba"
for(int i =0; i < str1.length; i++)
for(int j =0; j < str2.length; j++)
if str1[i+j]!=str[j]
break;
if( j ==str2.length -1)
i=i+str2.length;
It seems that you want to use step parameter of range function. From documentation:
range(start, stop[, step]) This is a versatile function to create
lists containing arithmetic progressions. It is most often used in for
loops. The arguments must be plain integers. If the step argument is
omitted, it defaults to 1. If the start argument is omitted, it
defaults to 0. The full form returns a list of plain integers [start,
start + step, start + 2 * step, ...]. If step is positive, the last
element is the largest start + i * step less than stop; if step is
negative, the last element is the smallest start + i * step greater
than stop. step must not be zero (or else ValueError is raised).
Example:
>>> range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> range(1, 11) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> range(0, 30, 5) [0, 5, 10, 15, 20, 25]
>>> range(0, 10, 3) [0, 3, 6, 9]
>>> range(0, -10, -1) [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
>>> range(0) []
>>> range(1, 0) []
In your case to get [0,2,4] you can use:
range(0,6,2)
OR in your case when is a var:
idx = None
for i in range(len(str1)):
if idx and i < idx:
continue
for j in range(len(str2)):
if str1[i+j] != str2[j]:
break
else:
idx = i+j
You might just be better of using while loops rather than for loops for this. I translated your code directly from the java code.
str1 = "ababa"
str2 = "aba"
i = 0
while i < len(str1):
j = 0
while j < len(str2):
if not str1[i+j] == str1[j]:
break
if j == (len(str2) -1):
i += len(str2)
j+=1
i+=1
In python, for loops iterate over iterables, instead of incrementing a counter, so you have a couple choices. Using a skip flag like Artsiom recommended is one way to do it. Another option is to make a generator from your range and manually advance it by discarding an element using next().
iGen = (i for i in range(0, 6))
for i in iGen:
print i
if not i % 2:
iGen.next()
But this isn't quite complete because next() might throw a StopIteration if it reaches the end of the range, so you have to add some logic to detect that and break out of the outer loop if that happens.
In the end, I'd probably go with aw4ully's solution with the while loops.
I read all the above answers and those are actually good.
look at this code:
for i in range(1, 4):
print("Before change:", i)
i = 20 # changing i variable
print("After change:", i) # this line will always print 20
When we execute above code the output is like below,
Before Change: 1
After change: 20
Before Change: 2
After change: 20
Before Change: 3
After change: 20
in python for loop is not trying to increase i value. for loop is just assign values to i which we gave. Using range(4) what we are doing is we give the values to for loop which need assign to the i.
You can use while loop instead of for loop to do same thing what you want,
i = 0
while i < 6:
print(i)
j = 0
while j < 5:
i += 2 # to increase `i` by 2
This will give,
0
2
4
Thank you !
for a in range(1):
for b in range(3):
a = b*2
print(a)
As per your question, you want to iterate the outer loop with help of the inner loop.
In outer loop, we are iterating the inner loop 1 time.
In the inner loop, we are iterating the 3 digits which are in the multiple of 2, starting from 0.
Output:
0
2
4
What is the equivalent list comprehension in python of the following Common Lisp code:
(loop for x = input then (if (evenp x)
(/ x 2)
(+1 (* 3 x)))
collect x
until (= x 1))
A list comprehension is used to take an existing sequence and perform some function and/or filter to it, resulting in a new list. So, in this case a list comprehension is not appropriate since you don't have a starting sequence. An example with a while loop:
numbers = []
x=input()
while x != 1:
numbers.append(x)
if x % 2 == 0: x /= 2
else: x = 3 * x + 1
I believe you are writing the hailstone sequence, although I could be wrong since I am not fluent in Lisp.
As far as I know, you can't do this in only a list comprehension, since each element depends on the last.
How I would do it would be this
def hailstone(n):
yield n
while n!=1
if n%2 == 0: # even
n = n / 2
else: # odd
n = 3 * n + 1
yield n
list = [ x for x in hailstone(input) ]
Of course, input would hold whatever your input was.
My hailstone function could probably be more concise. My goal was clarity.
Python doesn't have this kind of control structure built in, but you can generalize this into a function like this:
def unfold(evolve, initial, until):
state = initial
yield state
while not until(state):
state = evolve(state)
yield state
After this your expression can be written as:
def is_even(n): return not n % 2
unfold(lambda x: x/2 if is_even(x) else 3*x + 1,
initial=input, until=lambda x: x == 1)
But the Pythonic way to do it is using a generator function:
def produce(x):
yield x
while x != 1:
x = x / 2 if is_even(x) else 3*x + 1
yield x
The hackery referred to by Laurence:
You can do it in one list comprehension, it just ends up being AWFUL python. Unreadable python. Terrible python. I only present the following as a curiosity, not as an actual answer. Don't do this in code you actually want to use, only if you fancy having a play with the inner workings on python.
So, 3 approaches:
Helping List 1
1: Using a helping list, answer ends up in the helping list. This appends values to the list being iterated over until you've reached the value you want to stop at.
A = [10]
print [None if A[-1] == 1
else A.append(A[-1]/2) if (A[-1]%2==0)
else A.append(3*A[-1]+1)
for i in A]
print A
result:
[None, None, None, None, None, None, None]
[10, 5, 16, 8, 4, 2, 1]
Helping List 2
2: Using a helping list, but with the result being the output of the list comprehension. This mostly relies on list.append(...) returning None, not None evaluating as True and True being considered 1 for the purposes of arithmetic. Sigh.
A=[10]
print [A[0]*(not A.append(A[0])) if len(A) == 1
else 1 if A[-1] == 2 else (A[-1]/2)*(not A.append(A[-1]/2)) if (A[-1]%2==0)
else (3*A[-1]+1)*(not A.append(3*A[-1]+1))
for i in A]
result:
[10, 5, 16, 8, 4, 2, 1]
Referencing the List Comprehension from within
3: Not using a helping list, but referring back to the list comprehension as it's being built. This is a bit fragile, and probably wont work in all environments. If it doesn't work, try running the code on its own:
from itertools import chain, takewhile
initialValue = 10
print [i if len(locals()['_[1]']) == 0
else (locals()['_[1]'][-1]/2) if (locals()['_[1]'][-1]%2==0)
else (3*locals()['_[1]'][-1]+1)
for i in takewhile(lambda x:x>1, chain([initialValue],locals()['_[1]']))]
result:
[10, 5, 16, 8, 4, 2, 1]
So, now forget that you read this. This is dark, dark and dingy python. Evil python. And we all know python isn't evil. Python is lovely and nice. So you can't have read this, because this sort of thing can't exist. Good good.
As Kiv said, a list comprehension requires a known sequence to iterate over.
Having said that, if you had a sequence and were fixated on using a list comprehension, your solution would probably include something like this:
[not (x % 2) and (x / 2) or (3 * x + 1) for x in sequence]
Mike Cooper's answer is a better solution because it both retains the x != 1 termination, and this line doesn't read cleanly.
1
I have discovered a truly marvelous proof of this, which this margin is too narrow to contain.
In all seriousness though, I don't believe you can do this with Python list comprehensions. They have basically the same power as map and filter, so you can't break out or look at previous values without resorting to hackery.