restarting for cycle iterating over list python3 - python

[python] 3.6
Hello, I was trying to iterate over a list with a for cycle, where I had to restart the cycle whenever a condition was confirmed.
In C I would do:
for(i = 0; i < 10; i++){
if(list[i] == something)
i = 0;
}
Here I was trying to do this:
for x in listPrimes:
if((num % x) == 0):
num /= x # divide by the prime
factorials.append(x)
x = 2 # reset to the first prime in the list?
which doesn't work correctly. What are the ways to reset the for to a certain iteration of the list? Do I have to do the for in some other way?
Thanks for your time

You could just use a while loop:
i = 0
while i < 10:
print("do something", i)
if random.random() < 0.2:
print("reset")
i = -1
i += 1
Specific to your example:
i = 0
while i < len(listPrimes):
x = listPrimes[i]
if num % x == 0:
num /= x
factorials.append(x)
i = -1
i += 1

You can use a while loop similarly to your C code.
while i < 10:
if list[i] == something:
i = 0
i += 1

Use itertools.takewhile util
Here is a contrived example:
import itertools
li = [1,2,3,4,5]
for i in range(1, 6):
print(list(itertools.takewhile(lambda x: x!=i, li)))
print("new cycle")
Output:
[]
new cycle
[1]
new cycle
[1, 2]
new cycle
[1, 2, 3]
new cycle
[1, 2, 3, 4]
new cycle

The while loop is the most elegant solution. Just for completeness you could wrap your list into custom generator and let this new iterable receive signal to reset the loop.
import time
def resetable_generator(li):
while True:
for item in li:
reset = yield item
if reset:
break
else:
raise StopIteration
x = range(10)
sum = 0
r = resetable_generator(x)
for item in r:
time.sleep(1)
sum += item
if item == 6:
sum += r.send(True)
print(sum)

Related

How to sum even numbers from a list and then remove them?

I have tried to add sum of even numbers of a list and I am successful but in my second part I am not able to delete even numbers from the list. For example my input is [1,2,4,6,5] and When I tried this given code below, the output for sum of even numbers was 8 and new list was [1,4,5]. I want output as sum of even numbers as 12 and new list is [1,5].
n=list(map(int, input("elements of array:-").strip().split()))
even_sum = 0
for num in n:
if num%2==0:
even_sum += num
n.remove(num)
else:
odd_sum += num
print(even_sum)
print(n)
Here is a slightly more pythonic way to achieve what you want:
L = [1,2,4,6,5]
Lsum = sum([int(elem % 2 == 0) * elem for elem in L])
Lnew = [elem for elem in L if elem % 2 == 1]
You shouldn't iterate over the list and modify it.
n = [1,2,4,6,5]
odd_list = []
even_sum = 0
for num in n:
if num%2==0:
even_sum += num
else:
odd_sum += num
odd_list.append(num)
Heres a more nicer way achieving that only. It is called list comprehension
n = [1, 2, 4, 6, 5]
even_list = [i for i in n if i%2==0]
even_sum = sum(even_list)
// The OP wants an odd list as a result, revised version:
n = [1, 2, 4, 6, 5]
odd_list = [i for i in n if i%2==1]
even_sum = sum(n) - sum(odd_list)
This is happening because during iteration you are skipping some of the elements by removing others from the same sequence...
You can iterate backwards through the list instead. This eliminates the need for copying elements to a new list.
Like this:
n=list(map(int, input("elements of array:-").strip().split()))
i = len(n) -1
while i >= 0:
if n[i] % 2 == 0:
even_sum += n[i]
del n[i]
else:
odd_sum += n[i]
i -= 1

I am merging to list with ascending order

If either i or j reach the end of their list range, how i copy the remainder of the other
list to the merge list
https://ibb.co/m9JzBYp
go to link if not get the question
def list_merge (x, y):
merge = []
i = 0
j = 0
total = len (x) + len(y)
while != total :
if x[i] < y[j]:
merge.append(x[i])
i += 1
if i >= len (x):
#how i copy the reminder
else :
merge.append(y[j])
j += 1
if j >= len (y):
#how i copy the reminder
return merge
EDIT - OP wanted the code in some specific way.. Please see second snippet.
Don't try to complicate your code.. just go with how you would do it manually and write the code.
def list_merge (x, y):
merged_list = []
i = 0
j = 0
# when one of them is empty, break out
while i < len(x) and j < len(y):
if x[i] <= y[j]:
merged_list.append(x[i])
i +=1
else:
merged_list.append(y[j])
j +=1
# if you are here, that means either one of the list is done
# so check the bounds of both lists and append the one which is not traversed
# x has some elements to add
# check how extend works... makes your code clean
if i != len(x):
merged_list.extend(x[i:])
else:
merged_list.extend(y[j:])
return merged_list
a = [1,3,5,7,10]
b = [2,4,6,8,100]
print(list_merge(a,b))
Output
[1, 2, 3, 4, 5, 6, 7, 8, 10, 100]
What OP needed
def list_merge (x, y):
merge = []
i = 0
j = 0
total = len (x) + len(y)
while len(merge) != total :
if x[i] < y[j]:
merge.append(x[i])
i += 1
if i >= len (x):
merge.extend(y[j:])
else:
merge.append(y[j])
j += 1
if j >= len (y):
merge.extend(x[i:])
return merge
a quite simple form:
def merge(*lists_in):
list_in = []
for l in lists_in:
list_in += l
i = 0
while True:
if i == list_in.__len__() -1:
break
if list_in[i] > list_in[i+1]:
temp = list_in[i]
list_in[i] = list_in[i+1]
list_in[i+1] = temp
i = 0
else:
i += 1
return list_in
Testing it:
list1 = [1,4]
list2 = [1,5,6]
list3 = [3,7,9,10]
print(merge(list1, list2, list3))
Out:
[1, 1, 3, 4, 5, 6, 7, 9, 10]
This can be solved rather nicely using deques, which allow you to efficiently look at and remove the first element.
from collections import deque
# A generator function that interleaves two sorted deques
# into a single sorted sequence.
def merge_deques(x, y):
while x and y:
yield (x if x[0] <= y[0] else y).popleft()
# When we reach this point, one of x or y is empty,
# so one of these doesn't yield any values.
yield from x
yield from y
# Makes a list by consuming the merged sequence of two deques.
def list_merge(x, y):
return list(merge_deques(deque(x), deque(y))

How do I loop through two lists only iterating one at a time?

Im trying to implement merge sort in python and I'd like to know what is the pythonic way of looping through two lists iterating only one of the lists each loop.
This is what I have now (using indexes)
def merge(array1, array2):
final = []
i = 0
j = 0
while i < len(array1) or j < len(array2):
if array1[i] <= array2[j]:
final.append(array1[i])
i += 1
elif array2[j] < array1[i]:
final.append(array2[j])
j += 1
# Finished one of the arrays
if i == len(array1):
final.extend(array2[j:])
break
elif j == len(array2):
final.extend(array1[i:])
break
return final
Thanks.
I'm not sure not sure your problem here is using indices, but there's a lot of unneeded code.
Firstly, we can change your initialisers to:
final, i, j = [], 0, 0
Next, if we change your while condition we can remove the breaks:
while i < len(array1) and j < len(array2):
Your elif isn't meaningful as it will always be true, we can thus make your if:
if array1[i] <= array2[j]:
final.append(array1[i])
i += 1
else:
final.append(array2[j])
j += 1
And now because we're automatically breaking out of the loop we don't need the breaks and can move the extends outside:
def merge(array1, array2):
final, i, j = [], 0, 0
while i < len(array1) and j < len(array2):
if array1[i] <= array2[j]:
final.append(array1[i])
i += 1
else:
final.append(array2[j])
j += 1
final.extend(array1[i:])
final.extend(array2[j:])
return final
This gives you smaller, more readable code without actually changing the way you're doing anything, that way you'll still understand it.
Note that we can perform:
final.extend(array1[i:])
final.extend(array2[j:])
outside the loop because one array will have contents, for example [7,9], while the other will be empty([]):
>>> final = [3,6]
>>> array1 = [3,6]
>>> array2 = [7,9]
>>> i = 2
>>> j = 0
>>> array1[i:]
[]
>>> array2[j:]
[7, 9]
>>> final.extend(array1[i:])
>>> final
[3, 6]
>>> final.extend(array2[j:])
>>> final
[3, 6, 7, 9]

Subsetting python list into positive/negative movements/trends

Sorry for creating this question but I have been stuck on this question for a while.
Basically I'm trying to take a list:
numbers=[1, 2, -1, -2, 4, 5]
And subset this list into a list of list that display positive/negative movements (or trends)
The end result is to have:
subset_list = [[1, 2], [-1, -2], [4, 5]]
Basically I have been using nested while functions to append a positive movement to the subset, and when the condition is not met, the subset is appended to subset_list and then evaluates if there is a negative movement.
I keep getting an IndexError, and so far subset_list only contains [[1, 2]]
Here is my code:
numbers = [1,2,-1,-2,4,5]
subset = []
subset_list = []
subset.append(numbers[0])
i = 1
while i < (len(numbers)):
if numbers[i] <= numbers[i+1]:
subset.append(numbers[i])
i+= 1
while subset[-1] <= numbers[i] or numbers[i] <= numbers[i+1]:
subset.append(numbers[i])
i += 1
subset_list.append(subset)
subset = []
i += 1
if numbers[i] > numbers[i+1]:
subset.append(numbers[i])
i+= 1
while subset[-1] <= numbers[i] or numbers[i] <= numbers[i+1]:
subset.append(numbers[i])
i+= 1
subset_list.append(subset)
subset = []
i += 1
Thanks!
-Jake
Here is a way to re-write this:
numbers=[1,2,-1,-2,4,5]
direction = True # positive or negative
prevdirection = True
res = [[numbers[0]]]
for previtem, item in zip(numbers[:-1], numbers[1:]):
direction = True if item - previtem > 0 else False
if direction != prevdirection:
res.append([])
prevdirection = direction
res[-1].append(item)
print(res)
In python, one tends not to use the actual indexes in a list very often. Try a for-loop instead, plus a check to see whether the trend changed or not (this treats zero as a distinct trend from positive or negative - you can pretty simply change same_direction to group it one way or the other):
def same_direction(num1, num2):
# both numbers are positive, both are negative, or both are zero
return ((num1 > 0 and num2 > 0) or
(num1 < 0 and num2 < 0) or
(num1 == num2))
numbers = [1, 2, -1, -2, 4, 5]
result = [[]] #list with one sublist ready
last_number = 0
for num in numbers:
if same_direction(num, last_direction):
# No need for a new sublist, put new number in last sublist
result[-1].append(num)
else:
# trend changed, new sublist and put the number in it
result.append([num])
If change in trends always go through the sign change, you can "group" items based on a sign using itertools.groupby():
>>> from itertools import groupby
>>>
>>> [list(v) for _, v in groupby(numbers, lambda x: x < 0)]
[[1, 2], [-1, -2], [4, 5]]
We are using _ as a variable name for a "throw-away" variable since we don't need the grouping key in this case.
This is what I came up with. It is close to what you have but a little easier to read. I avoid having to increment the index counter i as much which is probably where you went wrong.
n= [1,2,-1,-2,4,5]
out=[]
i=1
tmp=[n[0]]
while i < len(n):
if n[i] >= 0 and tmp[-1] >= 0:
tmp.append(n[i])
elif n[i] < 0 and tmp[-1] < 0:
tmp.append(n[i])
else:
out.append(tmp)
tmp = [n[i]]
i = i + 1
if len(tmp) > 0: # typo fix was > 1
out.append(tmp)
print(out)
Here is my solution:
numbers = [1,2,-1,-2,4,5, 3, 2]
subset = []
subset_list = []
subset.append(numbers[0])
forward = 1
for i in range(0, len(numbers) - 1):
if ( forward == 1 ):
if numbers[i] <= numbers[i+1]:
subset.append(numbers[i+1])
else:
subset_list.append(subset)
subset = []
subset.append(numbers[i+1])
forward = 0
else:
if numbers[i] >= numbers[i+1]:
subset.append(numbers[i+1])
else:
subset_list.append(subset)
subset = []
subset.append(numbers[i+1])
forward = 1
subset_list.append(subset)
print(*subset)
print(*subset_list)
Unfortunately, I only have python 3 on my system so my answer is in python 3.

Python: while loop inside else

def is_prime(x):
count = 1
my_list = []
while count > 0 and count < x:
if x % count == 0:
my_list.append(x/count)
count += 1
return my_list
my_list = is_prime(18)
def prime(x):
my_list2 = []
for number in my_list:
if number <= 2:
my_list2.append(number)
else:
count = 2
while count < number:
if number % count == 0:
break
else:
my_list2.append(number)
count += 1
return my_list2
print prime(18)
Just started out with Python. I have a very simple question.
This prints: [9, 3, 2].
Can someone please tell me why the loop inside my else stops at count = 2? In other words, the loop inside my loop doesn't seem to loop. If I can get my loop to work, hopefully this should print [2, 3]. Any insight is appreciated!
Assuming that my_list2 (not a very nice name for a list) is supposed to contain only the primes from my_list, you need to change your logic a little bit. At the moment, 9 is being added to the list because 9 % 2 != 0. Then 9 % 3 is tested and the loop breaks but 9 has already been added to the list.
You need to ensure that each number has no factors before adding it to the list.
There are much neater ways to do this but they involve things that you may potentially find confusing if you're new to python. This way is pretty close to your original attempt. Note that I've changed your variable names! I have also made use of the x that you are passing to get_prime_factors (in your question you were passing it to the function but not using it). Instead of using the global my_list I have called the function get_factors from within get_prime_factors. Alternatively you could pass in a list - I have shown the changes this would require in comments.
def get_factors(x):
count = 1
my_list = []
while count > 0 and count < x:
if x % count == 0:
my_list.append(x/count)
count += 1
return my_list
# Passing in the number # Passing in a list instead
def get_prime_factors(x): # get_prime_factors(factors):
prime_factors = []
for number in get_factors(x): # for number in factors:
if number <= 2:
prime_factors.append(number)
else:
count = 2
prime = True
while count < number:
if number % count == 0:
prime = False
count += 1
if prime:
prime_factors.append(number)
return prime_factors
print get_prime_factors(18)
output:
[3, 2]
Just to give you a taste of some of the more advanced ways you could go about doing this, get_prime_factors could be reduced to something like this:
def get_prime_factors(x):
prime_factors = []
for n in get_factors(x):
if n <= 2 or all(n % count != 0 for count in xrange(2, n)):
prime_factors.append(n)
return prime_factors
all is a built-in function which would be very useful here. It returns true if everything it iterates through is true. xrange (range on python 3) allows you to iterate through a list of values without manually specifying a counter. You could go further than this too:
def get_prime_factors(x):
return [n for n in get_factors(x) if n <= 2 or all(n % c != 0 for c in xrange(2, n))]

Categories