Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I am trying to add a 0 after each even number, every time i run the code it infinitely prints the value of i, which is 0 every time.
I've tried this so far:
def linear_list (n):
x = []
for y in range (1, n+1):
x.append (y)
return x
n = int (input ("Enter the lenght of the list: "))
alist = linear_list (n)
for i in alist:
print (i)
if i % 2 == 0:
alist.append(0)
print (alist)
But for i >= 2my code is printing infinite zeroes:
Enter the lenght of the list: 5
0
0
0
0
...
Expected output:
[1, 2, 0, 3, 4, 0, 5, 6, 0, 7, 8, 0, 9, 10, 0]
How can achieve the correct list?
Make it work, make it right, make it fast
Here the make it work part.
You are modifying the list and iterating it at the same time.
Try:
otherlist = []
for i in alist:
print (i)
otherlist.append(i)
if i % 2 == 0:
otherlist.append(0)
print (otherlist)
You're increasing the alist length every time you append to it, and since you're looping through it you will never exit the loop - the list never ends. You don't want to change the list, but the value within it, so enumerate it:
for i, v in enumerate(alist):
print (v)
if v % 2 == 0:
alist[i] = v * 10 # assuming it's a number, use v + "0" if its a string
The iterator create by the for loop is a separate object from the list you iterate over. Your for loop is similar to a while loop like
itr = iter(a)
while True:
try:
i = next(itr)
except StopIteration:
break
if i % 2 == 0:
a.append(0)
a.append always adds a 0 to the end of the list, without affecting the current position of the iterator. Since 0 is even, once the iterator reaches the what was the end of the list when you started the loop, it sees a 0, and so another 0 gets added to the end of the list. It continues reading the next 0 and adding another 0, on and on, forever.
Technically, you can do what you want, but it's rather tricky and very easy to get wrong. (It took me about 8 tries to get this example right.) The trick is to create a separate iterator explicitly, one that you can access in the body of the loop, rather than letting the for loop generate the iterator for you. This allows you to insert a 0 after the current value in the list, then skip over the new 0 so that you won't see it on the next iteration of the loop.
Don't actually do this if you can avoid it: it is far simpler to create a new list that replaces the old list after the loop.
That said, on with the show:
a = range(10)
itr = enumerate(a) # A list of index, value pairs
for index, value in itr:
if value % 2 == 0:
i = index + 1
a[i:i] = [0] # Put a 0 after the current position
next(itr) # Skip over the 0 you just added
assert a == [0, 0, 1, 2, 0, 3, 4, 0, 5, 6, 0, 7, 8, 0, 9]
You can shorten this a bit by starting the index at 1 instead of 0, effectively pre-adding 1 to each index before you need it.
a = range(10)
itr = enumerate(a, start=1)
for i, value in itr:
if value % 2 == 0:
a[i:i] = [0]
next(itr)
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 months ago.
Improve this question
So I am trying to make a searching function. But that doesn't work right everytime. Gives the right output sometimes tough. Here is what i did:
import random
def normal_search(l, target):
# printing the list
l1 = l
x = ' '.join([str(l)])
print(f'The list is {x}')
choose = random.choice(l)
if choose == target:
index = l.index(choose)
index += 1
print(f"I found it! It's {index}. element.")
while choose != target:
l.remove(choose)
choose = random.choice(l)
print(choose)
index = l1.index(choose)
index += 1
print(f"normal_search I found it! It's {index}. element.")
# creating a shuffled list of 0 to 10
a = []
n = 0
while len(a) < 10:
n += 1
a.append(n)
random.shuffle(a)
normal_search(a, 5)
I am trying to get the target as output. What is making the output wrong?
I think the error is due to the fact that every time it does not find the target element the list decreases by 1 and if the removed element is before the target element it will change index.
I think the only solution is to stop removing the wrong elements, this would guarantee the correct functioning of the program but would increase its execution times.
import random
def normal_search(l, target):
# printing the list
x = ' '.join([str(l)])
print(f'The list is {x}')
while True:
choose = random.choice(l)
if choose == target:
index = l.index(choose)
index += 1
print(f"normal_search I found it! It's {index}. element.")
break
# creating a shuffled list of 0 to 10
a = list(range(10))
random.shuffle(a)
normal_search(a, 5)
As #FraRomee said, you are removing one element every step, suppose at first you have a list like: [0, 6, 4, 2, 3, 5, 1, 8, 9, 7], and index(5) is 6 and you randomly choose an element: 3 and it is not equal to 5 and you remove it, then you have [0, 6, 4, 2, 5, 1, 8, 9, 7] and length of list is 9 and index(5) is 5
and so on you choose 6 and remove it and you have [0, 4, 2, 5, 1, 8, 9, 7].
so if this time you select 5 correctly, index is 4 and it is correct for new list but is wrong for initial list and you cant use it for your own.
my code points:
you can create a list from a to b using list(range(a,b+1)) and you don't need while loop.
you can choose all elements from first in while body using break statement. if condition is False, so break loop, if not, go on and choose a new element.
I don't need an answer, just a jumping off point if possible.
I've made a multiplication table that prints 1-10, but my professor would like to see the table stored in a 2D list. I have my current code (working code, which is posted here), and new code I've made specifically for the "2D List" version, but I'm getting nowhere with either.
EDIT: I should probably clarify that the code is doing what I want it to do, which is outputting a multiplication table, but I am having trouble converting it into a 2D list.
#Initial list and global variables
MT = ["X", 1, 2, 3, 4, 5, 6, 7, 8, 9 ,10]
mult = 1
jump = 0
repeat = 1
list = 1
while repeat < 12:
index = 1
mult = 1
jump += 1
MT.append(MT[list])
while (index < 11):
MT.append(mult * jump)
mult += 1
index += 1
else:
repeat += 1
list += 1
else:
print("Multiplication Table:")
index = 0
while (index < 121):
if (((index + 1) % 11) != 0):
print(MT[index], end = "\t")
else:
print(MT[index], end = "\n")
index += 1
My first suggestion would be to start off with a 2D list:
MT = [["X", 1, 2, 3, 4, 5, 6, 7, 8, 9 ,10]]
rather than what you have.
Start a new empty list right before the inner while loop. You can initialize it with the first value new_row = [repeat]. Inside that loop append to the new_row rather than MT
After that while loop is done, you can append the new_row to MT
MT.append(new_row)
That should get you started with the 2d list. However, while I have you here...
If you need to repeat and keep track of how many times you've repeated, then use a for loop rather than a while loop.
For example, if you want a loop that goes from 2 to 12 you'd use:
for repeat in range(2, 13):
print(repeat)
Also, never overwrite built-in keywords as that can lead to unexpected behavior. So name list something else but I don't think that variable is really needed since it is similar to repeat.
>>> 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)
My task is to remove all instances of one particular element ('6' in this example) and move those to the end of the list. The requirement is to traverse a list making in-line changes (creating no supplemental lists).
Input example: [6,4,6,2,3,6,9,6,1,6,5]
Output example: [4,2,3,9,1,5,6,6,6,6,6]
So far, I have been able to do this only by making supplemental lists (breaking the task's requirements), so this working code is not allowed:
def shift_sixes(nums):
b = []
c = 0
d = []
for i in nums:
if i == 6:
b.insert(len(nums),i)
elif i != 6:
c = c +1
d.insert(c,i)
ans = d + b
return ans
I've also tried list.remove() and list.insert() but have gotten into trouble with the indexing (which moves when I insert() then move the element to the end): For example -
a = [6,4,6,2,3,6,9,6,1,6,5]
def shift_sixes(nums):
for i in nums:
if i == 6:
nums.remove(i)
nums.insert(nums[len(nums)-1], 0)
elif i != 0:
i
shift_sixes(a)
Additionally, I have tried to use the enumerate() function as follows, but run into problems on the right hand side of the b[idx] assigment line:
for idx, b in enumerate(a):
a[idx] = ???
Have read other stackoverflow entries here, here and here, but they do not tackle the movment of the element to one end.
Would appreciate any help on this list traversal / inplace switching issue. Many thanks.
EDIT
#eph - thank you. this is indeed an elegant response. I am sure it will pass my 'no new list' requirement? I surely intend to learn more about lambda and its uses
#falsetru - thank you for the reminder of the append/pop combination (which I tried to do in my original query via list.remove() and list.insert()
#tdelaney - thank you as well. somehow your response is closest to what I was attempting, but it seems not to pass the test for [0, 0, 5].
It is a bad idea to modify list while traverse. You can either make a copy to traverse, or generate a new list during traverse.
In fact, the question can be done in many ways, such as:
>>> a.sort(key = lambda i: i == 6)
>>> a
[4, 2, 3, 9, 1, 5, 6, 6, 6, 6, 6]
Iterating the list reverse way, pop the element if it's 6, then append it.
xs = [6,4,6,2,3,6,9,6,1,6,5]
for i in range(len(xs)-1, -1, -1): # 10 to 0
if xs[i] == 6:
xs.append(xs.pop(i))
Why not try something like this?
Basically, the approach is to first count the number of values.
If 0, then returns (since Python produces a ValueError if the list.index method is called for an element not in the list).
We can then set the first acceptable index for the value to be the length of the list minus the number of occurrences it exists in the list.
We can then combine list.pop/list.append to then traverse the list until all the values desired occur at the end of the list.
def shift_value(lst, value):
counts = lst.count(value) # 5
if not counts:
return lst
value_index = len(lst) - counts
index = lst.index(value)
while index != value_index:
lst.append(lst.pop(index))
index = lst.index(value)
return lst
lst = [6,4,6,2,3,6,9,6,1,6,5]
print(shift_value(lst, 6))
EDIT: This is horribly inefficient, better answer suggested above.
This requires O(n^2) time, rather than O(n) time.
The key term here is "In Line". The way you do that is move num[i] = num[i+1] for each i to the end of the list.
def shift_sixes(num):
for i, val in enumerate(num):
if val == 6:
# shift remaining items down
for j in range(i,len(num)-1):
num[j] = num[j+1]
# add 6 at the end
num[-1] = 6
return num
print(shift_sixes([1,9,4,6,2,7,8,6,2,2,6]))
print(shift_sixes([1,2,3]))
print(shift_sixes([6]))
print(shift_sixes([3]))
Use two runners. First from front to end checking for 6s, second from end to front pointing to last item that's not a 6. Keep swapping (a[i+1], a[i] = a[i], a[i+1]) until they meet.
Catch: this is not stable like in a stable sort. But I don't see that as a requirement.
Will try to write working code when in front of a python interpreter with a keyboard.
In case you need a stable sort (i.e. order of elements that are not 6 should remain the same), then the solution is:
def move_to_end(data, value):
current = 0 # Instead of iterating with for, we iterate with index
processed = 0 # How many elements we already found and moved to end of list
length = len(data) # How many elements we must process
while current + processed < length: # While there's still data to process
if data[current] == value: # If current element matches condition
data.append(data.pop(current)) # We remove it from list and append to end
processed += 1 # Our index remains the same since list shifted, but we increase number of processed elements
else: # If current element is not a match
current += 1 # We increase our index and proceed to next element
if __name__ == '__main__':
print
print 'Some testing:'
print
for test_case in (
[1, 9, 4, 6, 2, 7, 8, 6, 2, 2, 6], # Generic case
[6, 6, 6, 6], # All items are 6
[1, 7], # No items are 6
[], # No items at all
):
print 'Raw:', test_case
move_to_end(test_case, 6)
print 'Becomes:', test_case
print
Note that this solution retains the order of not only non-matching elements, but of matching elements as well. So for example, if you change the check condition from "equal to 6" to "is an even number", all elements matching the condition will be moved to the end of list while retaining their order among themselves.
Why not keep it simple?
a = [6,4,6,2,3,6,9,6,1,6,5]
def shift_sixes(nums):
for i in range(0,len(nums)):
if nums[i] == 6:
nums.append(nums.pop(i))
>>> shift_sixes(a)
>>> a
[3, 9, 1, 5, 2, 4, 6, 6, 6, 6]
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am brand new to python. I have been learning this on my own. I always make sure to exhaust every resource before asking a question on here.
but I will show you two sets of code. One does what I want, the other doesn't the only difference that appears to me, is how the ranges are set up. I don't understand the significance of this difference. Could someone please explain?
Thank you.
Code that works
def geometric(lst):
'checks whether the integers in list lst form a geometric sequence'
if len(lst) <= 1:
return True
ratio = lst[1]/lst[0]
for i in range(1, len(lst)-1):
if lst[i+1]/lst[i] != ratio:
return False
return True
**code that doesn't **
def geometric(integerList):
'checks whether the integers in list lst form a geometric sequence'
if len(lst) <= 1:
return True
ratio = integerList[1]/integerList[0]
for i in range (integerList[0], len(integerList))
if lst[i+1]/lst[i] != ratio:
return False
return True
In the first case, range(1, len(lst)-1) is a list
1, 2, 3, ..., len(lst)-1
In the second case, it depends on the value of the first list element. If integerList[0] is 3, then range() is
3, 4, 5, ..., len(lst)-1
and the first call of the if() statement compares integerList[4] / integerList[3] and ignores the first three elements in the list. So, the code only works, if integerList[0] == 1
However, there are two further pitfalls:
range() only takes integers as elements. If the first element is a float, pyhon will throw an error.
If the ratio always is an integer, you can compare the ratios for equality, as you do. But if ratio is a floating value, you can get into trouble: Though two ratios are mathematically equal, a computer (due to its floating point arithmetic) may calculate slightly different values. It is better to use
import math
...
if (math.fabs(lst[i+1]/lst[i] - ratio) < smallNumber)
where smallNumer is a very small number suitable for you.
By the way: In your second code, you use lst[] , but I guess, it was just a typo.
As Noelkd said, the range in your second code block starts with the value of the first element of the list, not its position.
If my list is the geometric sequence (1, 2, 4, 8, 16), your first block's range is
range(1, len(lst)-1) =
range(1, 5 - 1) =
range(1, 4) =
[1, 2, 3]
and your second block's range is
range(integerList[0], len(integerList)) =
range(1, 5) =
[1, 2, 3, 4]
This difference gets even weirder if my sequence doesn't start with 1, such as for the sequence (3, 9, 27):
First block's range is
range(1, len(lst)-1) =
range(1, 3 - 1) =
range(1, 2) =
[1]
and second block's range is
range(integerList[0], len(integerList)) =
range(3, 3) =
[]
for i in range(1, len(lst)-1):
...
This code first creates a list containing the numbers [1,2,3,...,len(lst)-1] and then loops over these values by setting i to a value in this list on every iteration.
for i in range (integerList[0], len(integerList))
This code actually creates a list containing the numbers:
[integerList[0],integerList[0] + 1,integerList[0] + 2,...,len(integerList)]
Here you're starting the range at integerList[0] not it's index. And if integerList[0] is bigger than len(integerList) you'll get an array with no values []
You also then try to use lst in the second function when really you're looking for integerList
This should help you understand what's happening:
>>> x = [2,4,5,6,7,8]
>>> for i in range(1,len(x)):
... print x[i]
...
4
5
6
7
8
So that's printing from the second to the last item.
>>> for i in range(x[0],len(x)):
... print x[i]
...
5
6
7
8
The second block is starting from x[0] which is 2 so from the third element to the last element.
Unless integerList[0] is always equal to 1 then you will not get the same range as range(1, len(lst)-1) which starts at 1, if integerList[0] == 5 your range will be range(5, len(integerList)) so you would miss elements from indexes 1 - 4 that you get in your first block of code and it would also throw an index error as lst[i+1] would be 1 index past the end of the list:
It would also be better to use enumerate:
def geometric(lst):
'checks whether the integers in list lst form a geometric sequence'
if len(lst) <= 1:
return True
ratio = lst[1] / lst[0]
for ind, ele in enumerate(lst[1:-1]):
if lst[ind+1] / ele != ratio:
return False
return True
In [4]: lst = ["foo","bar","foobar"]
In [5]: for ind, ele in enumerate(lst):
...: print ind,ele
...:
0 foo
1 bar
2 foobar