I would like to generate two infinitive series of 0 and 1 and specifically in the following order:
0, 1, 0, -1, 0, 1, 0, -1, ...
I have created the following code which does not return what except:
# for in loop
for i in itertools.cycle(range(0,2)):
if i == 0:
i += 1
if i == 1:
i -= 1
if i == 0:
i -= 1
print(i, end = " ")
It just returns a series of -1. Cannot figure out where the error is. Can anyone give any suggestions
You can use itertools.cycle() in a way that explicitly states the elements you want to generate:
from itertools import cycle
cycle([0, 1, 0, -1])
As an alternative, you can implement your own generator with some simple modular arithmetic:
def seq():
i = 0
while True:
yield (-1)**(i // 2) * (i % 2)
i = (i + 1) % 4 # keeps i small, so as not to take up too much memory
Demo:
>>> s = seq()
>>> [next(s) for _ in range(10)]
[0, 1, 0, -1, 0, 1, 0, -1, 0, 1]
I know OP states that they specifically want to use itertools, but this may still be helpful to others.
As pointed out in a comment, you can also simply emulate itertools.cycle by passing arbitrary args and using yield from (note that itertools.cycle actually works differently under the hood):
def seq(*args):
while True:
yield from args
s = seq(0, 1, 0, -1)
But that's not as fun as figuring out the actual arithmetic sequence in my opinion :D
Not sure why you're insisting on using itertools.cycle in a for loop like this, but here's one way you could make this work:
for i in itertools.cycle(range(0, 2)):
if i == 0:
print(i, end=" ")
i += 1
print(i, end=" ")
i -= 1
print(i, end=" ")
i -= 1
print(i, end=" ")
Note that there's really no point in using your nested if statements, since each nested predicate will always be true: if i is zero, and then you add one to it, then of course your nested predicate if i == 1 will be true...
In addition, your use of itertools.cycle in a for loop is an anti-pattern. As shown in BrokenBenchmark's answer, you can simply cycle over the elements of the sequence itself, forever. If you insist on using the for loop:
for i in itertools.cycle([0, 1, 0, -1]):
print(i, end=" ")
There are so many things wrong with this approach though. Namely, as I discussed in the comments, this is an infinite loop which is a fundamentally different behavior than an infinite sequence. With an infinite loop, nothing else can ever happen -- your program will be stuck cycling over your four elements forever with no way to do anything else.
If you use itertools.cycle as it's meant to be used -- as a generator -- you can pick up where you left off in the sequence at any time, allowing you to perform other tasks for as long as you want before continuing your sequence:
c = itertools.cycle((0, 1, 0, -1))
next(c) # 0
next(c) # 1
next(c) # 0
next(c) # -1
# do something else for a while
next(c) # 0
# yield the next 10 items from the sequence
for _ in range(10):
print(next(c), end=" ")
# do something else again
Related
beginner programmer!
sorry for the strangely worded question. I'm not sure how to word it; I might just be googling the wrong thing :/
I want to check for patches in a list that have 3 zeros in a row and change the middle 0 into a 2. For example:
[0, 0, 0, 0, 1]
would become
[0, 2, 0, 0, 1]
the second 0 became a two because the function detected 3 zeros in a row and changed the middle zero into a 2.
I used slices to write a for loop like this:
# create function
def test(lst):
# for loop for every object in list--
for i in lst:
# creates slice object.
# calls index method does the same here
# to find item index except it adds one
# then subtracts one to make the slice 3 objects
slce = str(lst.index(i) - 1) + ":" + str(lst.index(i) + 2)
print(slce)
It's not really a slice, it's a string, but I wanted to print it. I used this same code as an actual slice.
It's supposed to return:
-1:2
0:3
1:4
2:5
and so on and so forth, but instead it returns
-1:2
0:3
0:3
0:3
0:3
Any ideas? thank you guys for your help!
I'm not sure why you attempted using a.index(i) as it wil not always be correct because it returns the first occurance of i.
A better approach would be to slide a window on the array and check for the condition.
a = [0, 0, 0, 0, 1]
slices = [(i, i+3) for i in range(len(a) - 2)] # Generate slices
for i, j in slices:
if all(x == 0 for x in a[i:j]): # Check if all elements in the subarray are zero
a[i+1] = 2 # Change middle element
I generated a slices array to match your initial approach but you can skip this step. The code can be reduced to just a signle loop:
a = [0, 0, 0, 0, 1]
for i in range(len(a) - 2):
if all(x == 0 for x in a[i:i+3]):
a[i+1] = 2
not realy sure what your purpose is here, but i would imagine it would look something like this, dunno if that works.
from random import randint
data = []
for i in range(100): data.append(randint(0,1))
print(data)
for i in range(0,len(data)):
if data[i:i+3] == [0,0,0] and data[i-1] != 2: # made an edit
data[i:i+3] = [0,2,0]
print(data)
lst = [3, 4, 1, 2, 9]
givenSum = 12
table = {}
x = 0
y = 0
for i in range(0, len(lst)):
table[givenSum - lst[i]] = 1
i += 1
for x in table:
for y in table:
if (x + y) == givenSum:
print(x, "and", y, "is equal to", givenSum)
break
This is the output
9 and 3 is equal to 12
3 and 9 is equal to 12
I don't know why it's being shown up twice. I need to find a pair of values that add up to the given sum and this is the only way I could think of. I only want it to show up once though any ideas on how I can do that?
There are better solutions, but to fix your issue making minimal changes to your code:
lst = [3, 4, 1, 2, 9]
givenSum = 12
for x in range(0, len(lst) - 1):
for y in range(x + 1, len(lst)):
if lst[x] + lst[y] == givenSum:
print(lst[x], "and", lst[y], "is equal to", givenSum)
break
This will print
3 and 9 is equal to 12
Note that the redundant table is completely removed from the code.
If you run it for a better test case:
lst = [3, 4, 5, 6, 7, 1, 2, 9]
it will print
3 and 9 is equal to 12
5 and 7 is equal to 12
First, to address why the looping continues and gives a second output, break can only break out of its immediate loop. Since you have a nested loop, the break only stops the for y in table: inner loop, but allows for x in table outer loop to move onto it's next iteration. So eventually, x is able to take the value of 3 later on, thus giving you the two outputs you see.
So, if you need a way to stop the iteration entirely when a solution is found, you need to either chain the break statements using a for else syntax (which arguably might be tough to read) as follows,
for x in table:
for y in table:
if (x + y) == givenSum:
print(x, "and", y, "is equal to", givenSum)
break #breaks from inner loop
else: #for else syntax: this block runs if and only if there was no break encountered during looping.
continue #jumps the outer loop to next iteration
break #this break is set at outer loop's level. Essentially, we can only reach this portion if there is a break in the inner loop.
For else says: run through the whole iteration, and if no break is found, executes the code in the else block. Essentially, the "else" of a "for else" is like a "for - no break".
However, one easier alternative is to use a function with a return (which also makes it easier to read the code).
def find_given_sum(lst, givenSum):
table = {}
x = 0
y = 0
for i in range(0, len(lst)):
table[givenSum - lst[i]] = 1
i += 1
for x in table:
for y in table:
if (x + y) == givenSum:
print(x, "and", y, "is equal to", givenSum)
return #this returns immediately out of the function, thus stopping the iteration.
Also, you could just repeat the break condition, but repeating code is generally not a good practice.
Hope this helps address why the two outputs are being printed. Now, as for the solution itself, there's actually a much better way to solve this. It builds upon the idea of compliments, which you seem to have a sense of in your table. But it doesn't require iteration over the table itself. As a hint: the ideal solution runs in O(n) time. I will not discuss the ideal solution, but hope this prompts you to find the best approach.
Looping twice for n elements costs you O(N^2) time, which is inefficient for large lists. Modified and tested the code to use hash map/dictionary to store the list elements and now it will take only O(N) time.
Map = dict()
lst = [3, 4, 1, 2, 9]
givenSum = 12
for i in range(0, len(lst)):
rem=givenSum-lst[i]
if rem in Map:
print lst[i],lst[Map[rem]]
else:
Map[lst[i]]=i
Store the value of each list element into the map whenever it does not exist in the map.
At each iteration, take the difference between givenSum and current element at that iteration and then search for that difference in the Map.
If it exists it means the pair exists or else not.
In this approach you are running the loop only once, which takes O(N) time because accessing elements in hash map is O(1)/constant time.
Use itertools to get the result
import itertools
sum = 10
lst = [3, 4, 1, 2, 9]
ans = list(filter(lambda x : x[0]+x[1] == sum,itertools.combinations(lst, 2)))
I'm new to python and trying to run a function that will, given one variable, count down to zero and then up to the original variable. the output should look something like this:
>>> functionname(5)
5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5
so far I've written the code below, but this doesn't count up all the way to the original variable. I guess I need to somehow save the variable in order to refer to it later, but I have no idea how to do that, since python automatically changes n as the function goes on.
def functionname(n):
n = orginal
while n > 0:
print n
n=n-1
print n
if n==0:
print n
n=n+1
I would be very grateful for some pointers, as I seem to be completely stuck at the moment.
Just count from negative to positive and use math:
def fn(n):
print ', '.join(str(abs(i)) for i in range(-n, n+1))
fn(5)
# 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5
Pointers:
If you already know the range you want to iterate over, it's much cleaner and more direct to use a for loop instead of a while.
You can use the range function to generate number sequences.
You can convert simple for loops into list-comprehensions as I did above.
The "simple" clean implementation of your requirements would look something like this:
def fn(n):
for i in range(n, 0, -1):
print i,
for i in range(n + 1):
print i,
Other notes:
range can count backwards too
The end argument to range isn't included in the range itself, that's why the second loop specifies n + 1 as the limit (instead of just n)
Adding a trailing comma on your print makes it add a space at the end instead of a line-break.
Your second block is an if n == 0: (which you know it is since the while loop terminated when n hit 0); presumably you want while n <= 5.
Note that there are nicer ways to accomplish the same thing in Python. For example, using a pair of ranges with itertools.chain to iterate each range one after another allows you to simplify to:
import itertools
def functionname(n):
for i in itertools.chain(range(n, 0, -1), range(n+1)):
print i
Personally, I'd do something like...
def count(n):
for x in range(n, -n, -1):
print(str(abs(x)) + ",")
At the suggestion of dlewin, here's a list comprehension of the same...
def count(n):
print(','.join(str(abs(x)) for x in range(n, -n, -1)))
You need a second while loop that starts at 0 and goes back up to "original".
Do you know about "for" loops yet? Those are better for counting.
Your idea about having original is correct however you are using the assignment operator the wrong way 'round. Also the if n==0 line should be another loop (while or for as suggested by other answers), counting back up to original.
So I'd start with copying the value from n to original like this:
original = n
Hope that helps!
You got some bad formatting there. Remember to indent properly for functions and while and if statements.
So first, set n to 5. Then count down from there until you reach 0 with a while loop:
while n != -1:
print n
n -= 1
Then after the loop breaks, count back up again and reset n to 0:
n = 0
while n < 6:
print n
n += 1
I want to know the number of zeros which first appear in a list, before any other number.
For example:
L1 = [0, 0, 0, 0, 0, 1, 2] - the output should be 5, which is the number of zeros.
L2 = [1, 0, 0, 0, 0, 0, 2] - the output should be zero. Although there are 5 zeros in this list but the list starts with 1.
Here is my code:
k = 0
for i in L1:
while i == 0:
k = k + 1
It doesn't work though. I think it is an infinite loop, but I don't know why.
Think of what will happen the first time i gets set to 0.
The while loop will start and never stop, because i is not changed within that loop.
You would be better off with something as per the following transcript, a slight modification of yours:
>>> list1 = [0,0,0,0,0,1,2]
>>> count = 0
>>> for item in list1:
... if item == 0:
... count = count + 1
... else:
... break
...
>>> print count
5
or the slightly shorter variation which breaks immediately for a non-zero value, adding one otherwise.:
>>> list1 = [0,0,0,0,0,1,2]
>>> count = 0
>>> for item in list1:
... if item != 0: break
... count = count + 1
...
>>> print count
5
As other commentators have said, the problem in your code is that you seem to misunderstand the meaning of the while keyword. That aside, for problems like these, I often prefer a more functional style:
>>> import itertools
>>> k = len(list(itertools.takewhile(lambda x: x == 0, L1)))
>>> k
5
>>> k = len(list(itertools.takewhile(lambda x: x == 0, L2)))
>>> k
0
If you are just beginning to get to know Python, playing around with what the itertools offers is well worth it.
My answer expands on paxdiablo's. Thanks to him for clarifying OP's intent with the L2 case, which I had misread.
While itertools is handy for this kind of thing, at the point you're at, I'd say mastering the basic language features is worthwhile.
In your code, you do this:
L1 = [0, 0, 0, 0, 0, 1, 2]
k = 0
for i in L1:
while i == 0:
k = k + 1
When you run that chunk of code on L1, it loops forever. Here's why:
for causes the code that's enclosed (meaning the code below that's set aside by indentation) to loop. So, your for i in L1: loop runs everything indented below it once for each thing in L1.
But, while does something similar. while tells Python to run the indented code below it over and over until the condition on the while statement is False.
So, in the case of L1, the first time through the for loop, i gets set to 0. Then, while i == 0: says to execute the code enclosed, k = k + 1, over and over again until i is no longer zero. Unfortunately, since the code in the while loop does not change the value of i, i will be zero until the end of time, so it runs forever, repeatedly adding one to k.
What you're looking for is an if statement, which will not loop. It will just run the enclosed code, or not, based on whether its test is true. So, instead of:
while i == 0:
k = k + 1
you can use
if i == 0:
k = k + 1
else:
break
Then, each time through the for loop, the code asks whether i is zero, and if so, only once, it adds one to k, then goes on to the next list element. To cover your L2 case, if you hit a number that is not zero, break exits the for loop and stops counting.
The answer presented with itertools is clever, useful, good to know, and probably what you'd want to use for very large lists, but since it appears you're just learning the language (and probably learning your first language), it's worth learning how to use for, while, and if correctly.
What you're thinking while does, is carry on as normal until the condition isn't met. What it really does, is repeat the code inside of the while as a loop until the condition isn't met.
Here's my solution, which tries to work as similarly to yours as possible, by carrying on counting until the number isn't a 0 then looking at how far it's come and breaking out of the for loop.
k = 0
for index,item in enumerate(L1):
if item != 0:
k = len(L1[:index])
break
I need to search for an item in a list around a given index with in a given radius. Currently I use this function to generate alternating offsets for the search:
def generateSearchIndizes(radius):
for i in range(1, radius + 1):
yield i
yield -i
The code that does the search looks something like this:
for i in generateSearchIndizes():
if pred(myList[baseIndex + i]):
result = myList[baseIndex + i]
break # terminate search when first item is found
My question is, is there a more elegant way to generate the search indizes, maybe without defining a special function?
is there a more elegant way to generate the search indices
I don't think there's a more elegant way. Your code is very simple and clear.
maybe without defining a special function?
Yes, that's definitely possible.
>>> [b for a in ((x,-x) for x in range(1, 10 + 1)) for b in a]
[1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8, -8, 9, -9, 10, -10]
Here's my go at it:
from itertools import chain
>>> list(chain(*zip(range(1, 7), range(-7, 0)[::-1])))
[1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6]
Adjust as needed. :)
Perhaps a generator expression?
for i in (x/2 * (x%2 * 2 - 1) for x in xrange(2, radius*2)):
print i
It is short and fits to your "without defining a special function" requirement...
But, franky, I'd still prefer to use that special function instead - just for the sake of having more clear code. :)
Why not just do this with an inner loop, instead of creating a funky generator:
found = False
for i_abs in range(1, radius+1):
for i in (i_abs, -i_abs):
listitem = myList[baseIndex + i]
if pred(listitem):
result = listitem
found = True
break # terminate search when first item is found
if found:
break
else:
# handling in case no match found for pred
Some other comments:
you never test the 0'th element
since you are testing from both left
and right, you should stop after
i_abs reaches the halfway mark
I don't like repeating list indexing operations,
would rather repeat a variable reference; so I
lifted out the repeated myList[baseIndex+i] and
assigned it to listitem
you should add some handling in case
there is no matching element found
instead of breaking from the inner loop (which
here requires an extra found variable to
break out of the outer for loop), you might
be better just returning result right from the
inner loop,
as in:
for i_abs in range(1, radius+1):
for i in (i_abs, -i_abs):
listitem = myList[baseIndex + i]
if pred(listitem):
return listitem
Then there is no break management or found variable required.
Why alternate -i, i? Just do:
for i in range(-radius, radius+1):
listitem = myList[baseIndex + i]
if pred(listitem):
return listitem
Or if you absolutely must approach from front and back to get the outermost pred-matcher, how about:
for i in sorted(range(-radius, radius+1), key=abs):
listitem = myList[baseIndex + i]
if pred(listitem):
return listitem
If you have to do this often, just build sorted(range(-radius,radius+1),key=abs) once and keep it around for future iterating.
If you absolutely must not use the 0'th element, just insert a if not i: continue at the start of your loop.
This appears to me at least as readable as a separate function -- and arguably more understandable:
radius = 3
for outerbounds in ((-r,r) for r in range(1,radius+1)):
for i in outerbounds :
print i
# -1
# 1
# -2
# 2
# -3
# 3
Your own solution, adding a yield 0 at the start of the generator, is the most straightforward (aka pythonic).
Here's an infinite offset generator with a different algorithm:
def gen_offsets():
offset= 0
yield offset
step= 1; sign= 1
while 1:
offset+= sign*step
yield offset
step+= 1; sign= -sign
A more fanciful (aka not-so-pythonic :) way to write the algorithm above is:
import itertools as it, operator as op
def gen_offsets():
steps= it.imap(op.mul, it.count(1), it.cycle( (1, -1) ))
offset= 0
yield offset
for step in steps:
offset+= step
yield offset