Python single line while loop - python

In Python, I am trying to make a variable increment in value while it is less than another number. I know that it is possible to do a for loop in the form (print(x) for x in range(1, 5)). My question is, is there a similar way to do a while loop in this form, such as x += 1 while x < y?

x = 0
y = 10
while x < y:
x +=1
>>> x
10
Well you can do it in a single line because Python allows that:
x = 0
while x < y: x +=1
It is not as readable, and it doesn't conform to PEP 8, but it is doable.

You can separate each statement with a semi-colon like so...
x = 0; y = 5
while(x < y): print(x); x=x+1

You could do something like this
n = 0
while n < 1000: rn += n if not (n % 3 and n % 5) else 0
What you are seeing is a conditional expression but it comes at the price of some reduced readability

Related

Find occurrence of a string in another string

Details:
There are two strings x and y.
Count the number of occurrence of y in x as follows:
Length of y is 3.
Increment the "count" value when y == x[i] x[i+2] x[i+4]
Example:
x = "aabbcc"
y = "abc"
output: 2
My Code:
def solution(x, y):
i, count = 0, 0
j = i + 2
k = i + 4
while i+4 < len(x):
cur = x[i]
while i < len(x) and i != j:
i += 1
while i < len(x) and i != k:
i += 1
count += 1
return count
solution(x, y)
I am getting count = 1. It should give count = 2
There's a couple of logic errors in your code.
The problem happens here:
while i < len(x) and i != j:
i += 1
res.append(x[i])
You keep increasing i until it is either len(x) or greater, or until it is the same as j. But since you set j to be 2 at the start (and never update it), it will simply end up setting i to len(x). And x[i] will thus fail, since x[len(x)] tries to index an element just outside x.
However, there's a few more remarks to make:
you collect what you find in res, but really only want a number (e.g. 2) as a result
you define count but don't use it
you track the coordinates in the string in three separate variables (i, j, k) and have a lot of logic to increment the first, but really all you need is to step through the string one position at a time, and look at the offsets directly
Given all that and the problem description, you were probably going for something like this:
x = "aabbcc"
y = "abc"
def solution(x, y):
i, count = 0, 0
while i + 4 < len(x):
if (x[i], x[i+2], x[i+4]) == (y[0], y[1], y[2]):
count += 1
i += 1
return count
print(solution(x, y))
However, Python has some cleverness that would make it even simpler (or at least shorter):
def solution(x, y):
count = 0
for i in range(len(x)-4):
if x[i:i+5:2] == y: # slicing with a stride of two, instead of direct indexing
count += 1
return count
Or even:
def solution(x, y):
return len([x for i in range(len(x)-4) if x[i:i+5:2] == y])
But that's favouring brevity over readability a bit too much, I feel.
A generator expression solution, taking advantage of True/False == 1/0 in a numeric context:
def solution(x, y):
return sum(y == x[i:i+5:2] for i in range(len(x)-4))
Increment the "count" value when y == x[i] x[i+2] x[i+4]
This is the same as simply creating the string consisting of x[0], x[2], x[4]... (every even-numbered character) and the string consisting of x[1], x[3], x[5]... (every odd-numbered character); counting the occurrences of y in each; and adding those two results together.
Creating the strings is trivial, and a common duplicate. Counting occurrences of a substring is also well-trodden ground. Putting these tools together:
def spread_substrings(needle, haystack):
even_haystack = haystack[::2]
odd_haystack = haystack[1::2]
return even_haystack.count(needle) + odd_haystack.count(needle)

How can i sequence for a range(5,10000) until it hits 1?

i am new to python and i am currently working on a task for my university. The question is the following:
Given that f(x) = x / 2 if x is even and f(x) = 3*x+1 if x is odd, how do i build a loop that picks a number from a range(5,10000) and sequences it for as long as if it hits 1, it stops. Right now i only accomplished that my loop sorts it in different lists. At least :D
This is my current code:
odd = []
even = []
for num in range (5,10000):
if num % 2 == 0:
even.append(sum)
else:
if num % 2 == 1:
odd.append(sum)
This is famous math problem known as Collatz conjecture to make it simple we will perform the function 2x if x is even and 3x+1 if x is odd till it becomes 1. 1 is the minimum possible value of this sequence.
import random
def collatz_sequence(x):
seq = [x]
if x < 1:
return []
while x > 1:
if x % 2 == 0:
x = x / 2
else:
x = 3 * x + 1
seq.append(x)
return seq
maxLength = -1
maxNum = 1
for num in range(5, 10001):
currseq = collatz_sequence(num)
print(currseq)
currseq_len = len(currseq)
if currseq_len > maxLength:
maxLength = currseq_len
maxNum = num
print(maxNum, maxLength)

Find first non zero numbers in an array (zeroes can be anywhere)

Suppose we have an array: x = [10,0,30,40]. I would like to extract the first non zero element and store it in a different variable, say y. In this example, y = 10. We can also have many zeros, x = [0,0,30,40], which should give y = 30 as the extracted value.
I tried a Python snippet like this:
i = 0
while x[i] != 0:
y = arr[i]
if x[i] == 0:
break
This only works if the array is [10,0,30,40]. It does not work if I have 0,20,30,40. The loop would stop before that. What is an efficient way to implement this? I try not to use any special Numpy functions, just generic common loops because I might need to port it to other languages.
You can do this
x = [10,0,30,40]
for var in x:
if var != 0:
y = var
break
You could use list comprehension to get all the non-zero values, then provided there are some non-zero values extract the first one.
x = [10,0,30,40]
lst = [v for v in x if v != 0]
if lst:
y = lst[0]
print(y)
The problem with your code is that you don't increment i so it's stuck on the first element. So what you could do to keep the code portable is:
while x[i] != 0:
y = x[i]
if x[i] == 0:
break
i+=1
This code is still not clean, because if there is no 0 in your array then you will get an IndexError as soon as you reach the end.
I'm kind of new to this but i think this should work:
x = [0, 12, 24, 32, 0, 11]
y = []
for num in x:
if num != 0:
y.append(num)
break
print(y)
You can use the next function:
x = [10,0,30,40]
next(n for n in x if n) # 10
x = [0,0,30,40]
next(n for n in x if n) # 30
if you need to support the absence of zero in the list, you can use the second parameter of the next() function:
x = [0,0,0,0]
next((n for n in x if n),0) # 0

While loop vs a for loop in finding sum of multiples of 3 and 5 under 1000

not really familiar with while loops but I thought it was an alternative so this may be an elementary mistake.
I need to look for the sum of natural numbers under 1000 that are multiples of 3 and 5. E.g for under 10
multiples of 3 and 5 < 10 = 3,5,6,9
sum = 23
My code using a for loop works and is as follows (this was my initial solution):
def multiple():
lst = []
for x in range(334): #didn't know how else to use a for loop but to find the largest value of x using a calculator
if 3*x < limit:
lst.append(3*x)
if 5*x< 1000:
lst.append(5*x)
if (3*x > 1000) and (5*x > 1000): #unnecessary in a forloop with a range but this is just to maintain symmetry with while loop
break
lst2 = list(set(lst)) #remove duplicates
print(sum(lst2))
multiple()
My code using a while loop(this solution doesn't even come out in te console --> maybe this is were the error lies):
def multiple():
lst = []
while True:
x = 1
if 3*x < 1000:
lst.append(3*x)
if 5*x< 1000:
lst.append(5*x)
if (3*x > 1000) and (5*x > 1000):
break
x += 1
lst2 = list(set(lst)) #remove duplicates
print(sum(lst2))
multiple()
Desired output:
233168
In addition to how to rectify the while loop, any improvements on my for loop or while loop would also be welcome. Thanks
Critically Debugging
Since you're new, let's take this opportunity to analyze the bug before we solve it. Note first that you did not notice any printouts at all. Therefore, your print() statement was either not running, or was printing only spaces. We can rule out the latter since sum() will return an integer.
Therefore, the print() is never run. The function is defined and called correctly, so that's not the issue. Now notice while True:; this is an early warning sign. If the while loop never ends, the print() will never run. We do notice there are multiple break statements that should stop the loop, but it's likely there's an issue with them.
Now we check how the loop updates. First, note the i+=1. That seems right. However, i=1 is also within the while loop. This cannot be correct, since every iteration i will be reset. This would cause the loop to run forever.
This type of critical analysis of code is only built through practice, but hopefully this answer offers some insight into how you could have fixed this issue yourself (and how I looked through your code).
Also note that adding print statements into the while loop to test would have allowed you to notice that i was always 1.
Working Code
def multiple():
lst = []
x = 1 # moved from line below
while True:
# x = 1 should not go here
if 3*x < 1000:
lst.append(3*x)
if 5*x< 1000:
lst.append(5*x)
if (3*x > 1000) and (5*x > 1000):
break
x += 1
lst2 = list(set(lst)) #remove duplicates
print(sum(lst2))
multiple()
A fairly straight forward approach is to iterate over every number from 1 to 1000 and check if it is divisible by 3 or 5, and then sum them all up.
total = sum(x for x in range(1, 1001) if x%3 == 0 or x%5 == 0)
total
# returns:
234168
Another solution:
Using for loop:
def multiple():
sum = 0
for _ in xrange(1, 1001):
if _ % 3 == 0 or _ % 5 == 0:
sum += _
return sum
print(multiple())
Using while loop:
def multiple():
sum = 0
cnt = 1
while cnt <= 1000:
if cnt % 3 == 0 or cnt % 5 == 0:
sum += cnt
cnt += 1
return sum
print(multiple())
output:
234168
#!/usr/bin/env python
def multiple():
lst = []
x=1
while (3*x < 1000) or (5*x < 1000):
if 3*x < 1000:
lst.append(3*x)
if 5*x < 1000:
lst.append(5*x)
x += 1
lst2 = list(set(lst)) #remove duplicates
print(sum(lst2))
multiple()

Euler Project No. 2 with Python

Can somebody tell me why this should be wrong?
#Each new term in the Fibonacci sequence is generated
#by adding the previous two terms. By starting with 1 and 2,
#the first 10 terms will be:
#1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
#Find the sum of all the even-valued terms in the sequence
#which do not exceed four million.
sum=2
list = [1,2]
for x in range(2,100):
a = list[x-2]+list[x-1]
print(a)
list.append(a)
if a % 2 == 0:
sum += a
print('sum', sum)
if sum >= 4000000:
break
Here's a completely different way to solve the problem using a generator and itertools:
def fib():
a = b = 1
while 1:
yield a
a, b = b, a + b
import itertools
print sum(n for n in itertools.takewhile(
lambda x: x <= 4000000, fib()) if n % 2 == 0)
Output:
4613732
So your code, even though it is wrong (see other answers), happens to give the correct answer.
replace
sum += a
print('sum', sum)
if sum >= 4000000:
break
with
if a > 4000000:
break
sum += a
print('sum', sum)
You should compare "a" with 4000000, not "sum", like Daniel Roseman said.
The question asked for the sum of even terms which do not exceed four million. You're checking if the sum doesn't exceed 4m.
I'm trying to solve the same problem - although I understand the logic to do it, I don't understand why this works (outputs the right sum)
limit = 4000000
s = 0
l = [1,2]
while l[-1]<limit:
n = l[-1]+l[-2]
l.append(n)
print n
And then then moment I put in the modulo function, it doesn't output anything at all anymore.
limit = 4000000
s = 0
l = [1,2]
while l[-1]<limit:
n = l[-1]+l[-2]
if n % 2 == 0 :
l.append(n)
print n
I'm sure this is fairly simple...thanks!
This is the code I used. It is very helpful and teaches you about generators.
def fib():
x,y = 0,1
while True:
yield x
x,y = y, x+y
def even(seq):
for number in seq:
if not number % 2:
yield number
def under_a_million(seq):
for number in seq:
if number > 4000000:
break
yield number
print sum(even(under_a_million(fib())))
-M1K3
Keep it simple and it should take you less than 0.1 seconds.
from datetime import datetime
x, y = 1, 1
total = 0
for i in xrange (1, 100):
x = x + y
if x % 2 == 0 and x <= 4000000:
total += x
y = y + x
if y % 2 == 0 and x <= 4000000:
total += y
print total
starttime = datetime.now()
print datetime.now() - starttime

Categories