I am thoroughly perplexed over the following behavior:
gap_in_y[i][j] = max((scoreMatrix[i-1][j] - dy), (gap_in_y[i-1][j] - ey))
if i == 3 and j == 1:
print gap_in_y
gap_in_x[i][j] = max((scoreMatrix[i][j-1] - dx), (gap_in_x[i][j-1] - ex))
if i == 3 and j == 1:
print gap_in_y
The two print statements produce arrays that are different in exactly one value: the value contained in gap_in_y[3][1]. Modifying gap_in_x, a separate array, shouldn't affect gap_in_y... but, somehow it does.
Any ideas? I've been going crazy trying to figure this out!
I created the two arrays in the following manner:
for i in range (0, ALength+1):
for j in range (0, BLength+1):
new.append("N/A")
gap_in_y.append(new)
gap_in_x.append(new)
new = []
It is hard to tell without seeing how gap_in_y and gap_in_x are created, but what is probably happening here is that gap_in_y[3] and gap_in_x[3] are both references to the same list, so modifying one will modify the other. You can check this out by adding the following code:
if i == 3:
print id(gap_in_y[3]) == id(gap_in_x[3])
If this ever prints True, then you know that you have copies of the same list in both of your nested lists.
When you do:
gap_in_x.append(new)
gap_in_y.append(new)
both lists will reference the same object new.
The simplest solution might be to change this to:
gap_in_x.append(new[:])
gap_in_y.append(new[:])
(assuming new is a list).
The slice operator [:] will create a copy of list new so each list will receive its own copy.
I see, when you created the array, you create a single new list, and append this same list into both the gap_in_x and gap_in_y lists. So they now contain the same list and any mutation in it will naturally be seen from either parent list.
Instead of appending new, append new[:], this will create a copy of new for each gap_in_*, as you have it now, it puts the same list into each of them.
for i in range (0, ALength+1):
for j in range (0, BLength+1):
new.append("N/A")
gap_in_y.append(new[:])
gap_in_x.append(new[:])
new = []
Other answers have pointed out the issue with the current code. I just want to suggest an alternative way of creating your lists, using list multiplication and a list comprehension rather than explicit loops and append():
gap_in_x = [["N/A"] * (BLength + 1) for _ in range(ALength + 1)]
gap_in_y = [["N/A"] * (BLength + 1) for _ in range(ALength + 1)]
Note that you don't want to use list multiplication for the outer list (e.g. [["N/A"] * BLength] * ALength) because this will cause a similar issue to what you're having already, where all of the inner lists will be copies of each other (though within the same outer array this time, not across the two). It's fine for the inner list because strings are immutable. It doesn't matter if some (or all) of the N/As reference the same object, since that object cannot modified.
Related
There are many ways to remove n items from the list, but I couldn't find a way to keep n items.
lst = ["ele1", "ele2", "ele3", "ele4", "ele5", "ele6", "ele7", "ele8", "ele9", "ele10"]
n = 5
lst = lst[:len(lst)-(len(lst)-n)]
print(lst)
So I tried to solve it in the same way as above, but the problem is that the value of 'lst' always changes in the work I am trying to do, so that method is not valid.
I want to know how to leave only n elements in a list and remove all elements after that.
The simplest/fastest solution is:
del lst[n:]
which tells it to delete any elements index n or above (implicitly keeping 0 through n - 1, a total of n elements).
If you must preserve the original list (e.g. maybe you received it as an argument, and it's poor form to change what they passed you most of the time), you can just reverse the approach (slice out what you want to keep, rather than remove what you want to discard) and do:
truncated = lst[:n] # You have access to short form and long form
so you have both the long and short form, or if you don't need the original list anymore, but it might be aliased elsewhere and you want the aliases unmodified:
lst = lst[:n] # Replaces your local alias, but leaves other aliases unchanged
very similar to the solution of ShadowRanger, but using a slice assignment on the left hand side of the assigment oparator:
lst[n:] = []
I am trying to append objects to the end of a list repeatedly, like so:
list1 = []
n = 3
for i in range(0, n):
list1 = list1.append([i])
But I get an error like: AttributeError: 'NoneType' object has no attribute 'append'. Is this because list1 starts off as an empty list? How do I fix this error?
This question is specifically about how to fix the problem and append to the list correctly. In the original code, the reported error occurs when using a loop because .append returns None the first time. For why None is returned (the underlying design decision), see Why do these list operations return None, rather than the resulting list?.
If you have an IndexError from trying to assign to an index just past the end of a list - that doesn't work; you need the .append method instead. For more information, see Why does this iterative list-growing code give IndexError: list assignment index out of range? How can I repeatedly add elements to a list?.
If you want to append the same value multiple times, see Python: Append item to list N times.
append actually changes the list. Also, it takes an item, not a list. Hence, all you need is
for i in range(n):
list1.append(i)
(By the way, note that you can use range(n), in this case.)
I assume your actual use is more complicated, but you may be able to use a list comprehension, which is more pythonic for this:
list1 = [i for i in range(n)]
Or, in this case, in Python 2.x range(n) in fact creates the list that you want already, although in Python 3.x, you need list(range(n)).
You don't need the assignment operator. append returns None.
append returns None, so at the second iteration you are calling method append of NoneType. Just remove the assignment:
for i in range(0, n):
list1.append([i])
Mikola has the right answer but a little more explanation. It will run the first time, but because append returns None, after the first iteration of the for loop, your assignment will cause list1 to equal None and therefore the error is thrown on the second iteration.
I personally prefer the + operator than append:
for i in range(0, n):
list1 += [[i]]
But this is creating a new list every time, so might not be the best if performance is critical.
Note that you also can use insert in order to put number into the required position within list:
initList = [1,2,3,4,5]
initList.insert(2, 10) # insert(pos, val) => initList = [1,2,10,3,4,5]
And also note that in python you can always get a list length using method len()
Like Mikola said, append() returns a void, so every iteration you're setting list1 to a nonetype because append is returning a nonetype. On the next iteration, list1 is null so you're trying to call the append method of a null. Nulls don't have methods, hence your error.
use my_list.append(...)
and do not use and other list to append as list are mutable.
This problem is very simple to appreciate, here is the program -
hisc = [1,2,3,4]
print("\n", hisc)
ohisc = hisc
hisc.append(5)
print("\nPreviously...", ohisc)
print("\nAnd now...", hisc)
input("\nETE")
When I run it ohisc gets the 5. Why does ohisc change? How can I stop it from changing?
Apologies if this is something obvious.
Python variables are references. As such, the assignment copies the reference rather than the content of the variable.
In order to avoid this, all you have to do is create a new object:
ohisc = list(hisc)
This is using the list constructor which creates a new list from a given iterable.
Alternatively you can also assign from a slice (which creates a new object):
ohisc = hisc[:]
[] is the general slice operator which is used to extract a subset from a given collection. We simply leave out the start and end position (they default to the begin and end of the collection, respectively).
You definitely need to understand everything in Konrad Rudolph's answer. And I think in your specific case, that's what you want, too. But often there's a better way: If you avoid mutating objects (that is, changing them in-place), it never matters whether two names are referring to the same object or not. For example, you can change this:
hisc.append(5)
to this:
hisc = hisc + [5]
That doesn't change hisc in-place; it creates a new list, with the 5 added on to the end of it, and then assigns that to hisc. So, the fact that ohisc was pointing to the same list as hisc doesn't matter—that list is still there, unchanged, for ohisc to point to.
Let's say you wanted to replace all the negative values of the list with 0. That's pretty easy with mutation:
for i in range(len(lst)):
list[i] = max(list[i], 0)
But even easier without:
lst = [max(elem, 0) for elem in lst]
Now, what if you wanted to remove every negative list element? You can't change the shape of a sequence while looping over it, so you have to either make a copy of the list (so you can loop over one copy while you change the other), or come up with a more complicated algorithm (e.g., swap each 0 backward and then remove all the 0's at the end). But it's easy to do immutably:
lst = [elem for elem in lst if elem >= 0]
So, when would you ever want to mutate? Well, often you want two references to the same object, so when you update one, the other one sees the changes. In that case, you obviously have to have actual changes for the other one to see.
Here's a good explanation of what is happening: Python: copying a list the right way
Basically, you're making a pointer to the list but what you want to do is make a copy of the list.
Try this instead:
hisc = [1,2,3,4]
ohisc = hisc[:]
I know that it is not allowed to remove elements while iterating a list, but is it allowed to add elements to a python list while iterating. Here is an example:
for a in myarr:
if somecond(a):
myarr.append(newObj())
I have tried this in my code and it seems to work fine, however I don't know if it's because I am just lucky and that it will break at some point in the future?
EDIT: I prefer not to copy the list since "myarr" is huge, and therefore it would be too slow. Also I need to check the appended objects with "somecond()".
EDIT: At some point "somecond(a)" will be false, so there can not be an infinite loop.
EDIT: Someone asked about the "somecond()" function. Each object in myarr has a size, and each time "somecond(a)" is true and a new object is appended to the list, the new object will have a size smaller than a. "somecond()" has an epsilon for how small objects can be and if they are too small it will return "false"
Why don't you just do it the idiomatic C way? This ought to be bullet-proof, but it won't be fast. I'm pretty sure indexing into a list in Python walks the linked list, so this is a "Shlemiel the Painter" algorithm. But I tend not to worry about optimization until it becomes clear that a particular section of code is really a problem. First make it work; then worry about making it fast, if necessary.
If you want to iterate over all the elements:
i = 0
while i < len(some_list):
more_elements = do_something_with(some_list[i])
some_list.extend(more_elements)
i += 1
If you only want to iterate over the elements that were originally in the list:
i = 0
original_len = len(some_list)
while i < original_len:
more_elements = do_something_with(some_list[i])
some_list.extend(more_elements)
i += 1
well, according to http://docs.python.org/tutorial/controlflow.html
It is not safe to modify the sequence
being iterated over in the loop (this
can only happen for mutable sequence
types, such as lists). If you need to
modify the list you are iterating over
(for example, to duplicate selected
items) you must iterate over a copy.
You could use the islice from itertools to create an iterator over a smaller portion of the list. Then you can append entries to the list without impacting the items you're iterating over:
islice(myarr, 0, len(myarr)-1)
Even better, you don't even have to iterate over all the elements. You can increment a step size.
In short: If you'are absolutely sure all new objects fail somecond() check, then your code works fine, it just wastes some time iterating the newly added objects.
Before giving a proper answer, you have to understand why it considers a bad idea to change list/dict while iterating. When using for statement, Python tries to be clever, and returns a dynamically calculated item each time. Take list as example, python remembers a index, and each time it returns l[index] to you. If you are changing l, the result l[index] can be messy.
NOTE: Here is a stackoverflow question to demonstrate this.
The worst case for adding element while iterating is infinite loop, try(or not if you can read a bug) the following in a python REPL:
import random
l = [0]
for item in l:
l.append(random.randint(1, 1000))
print item
It will print numbers non-stop until memory is used up, or killed by system/user.
Understand the internal reason, let's discuss the solutions. Here are a few:
1. make a copy of origin list
Iterating the origin list, and modify the copied one.
result = l[:]
for item in l:
if somecond(item):
result.append(Obj())
2. control when the loop ends
Instead of handling control to python, you decides how to iterate the list:
length = len(l)
for index in range(length):
if somecond(l[index]):
l.append(Obj())
Before iterating, calculate the list length, and only loop length times.
3. store added objects in a new list
Instead of modifying the origin list, store new object in a new list and concatenate them afterward.
added = [Obj() for item in l if somecond(item)]
l.extend(added)
You can do this.
bonus_rows = []
for a in myarr:
if somecond(a):
bonus_rows.append(newObj())
myarr.extend( bonus_rows )
Access your list elements directly by i. Then you can append to your list:
for i in xrange(len(myarr)):
if somecond(a[i]):
myarr.append(newObj())
make copy of your original list, iterate over it,
see the modified code below
for a in myarr[:]:
if somecond(a):
myarr.append(newObj())
I had a similar problem today. I had a list of items that needed checking; if the objects passed the check, they were added to a result list. If they didn't pass, I changed them a bit and if they might still work (size > 0 after the change), I'd add them on to the back of the list for rechecking.
I went for a solution like
items = [...what I want to check...]
result = []
while items:
recheck_items = []
for item in items:
if check(item):
result.append(item)
else:
item = change(item) # Note that this always lowers the integer size(),
# so no danger of an infinite loop
if item.size() > 0:
recheck_items.append(item)
items = recheck_items # Let the loop restart with these, if any
My list is effectively a queue, should probably have used some sort of queue. But my lists are small (like 10 items) and this works too.
You can use an index and a while loop instead of a for loop if you want the loop to also loop over the elements that is added to the list during the loop:
i = 0
while i < len(myarr):
a = myarr[i];
i = i + 1;
if somecond(a):
myarr.append(newObj())
Expanding S.Lott's answer so that new items are processed as well:
todo = myarr
done = []
while todo:
added = []
for a in todo:
if somecond(a):
added.append(newObj())
done.extend(todo)
todo = added
The final list is in done.
Alternate solution :
reduce(lambda x,newObj : x +[newObj] if somecond else x,myarr,myarr)
Assuming you are adding at the last of this list arr, You can try this method I often use,
arr = [...The list I want to work with]
current_length = len(arr)
i = 0
while i < current_length:
current_element = arr[i]
do_something(arr[i])
# Time to insert
insert_count = 1 # How many Items you are adding add the last
arr.append(item_to_be inserted)
# IMPORTANT!!!! increase the current limit and indexer
i += 1
current_length += insert_count
This is just boilerplate and if you run this, your program will freeze because of infinite loop. DO NOT FORGET TO TERMINATE THE LOOP unless you need so.
a=[]
a.append(3)
a.append(7)
for j in range(2,23480):
a[j]=a[j-2]+(j+2)*(j+3)/2
When I write this code, it gives an error like this:
Traceback (most recent call last):
File "C:/Python26/tcount2.py", line 6, in <module>
a[j]=a[j-2]+(j+2)*(j+3)/2
IndexError: list assignment index out of range
May I know why and how to debug it?
Change this line of code:
a[j]=a[j-2]+(j+2)*(j+3)/2
to this:
a.append(a[j-2] + (j+2)*(j+3)/2)
You're adding new elements, elements that do not exist yet. Hence you need to use append: since the items do not exist yet, you cannot reference them by index. Overview of operations on mutable sequence types.
for j in range(2, 23480):
a.append(a[j - 2] + (j + 2) * (j + 3) / 2)
The reason for the error is that you're trying, as the error message says, to access a portion of the list that is currently out of range.
For instance, assume you're creating a list of 10 people, and you try to specify who the 11th person on that list is going to be. On your paper-pad, it might be easy to just make room for another person, but runtime objects, like the list in python, isn't that forgiving.
Your list starts out empty because of this:
a = []
then you add 2 elements to it, with this code:
a.append(3)
a.append(7)
this makes the size of the list just big enough to hold 2 elements, the two you added, which has an index of 0 and 1 (python lists are 0-based).
In your code, further down, you then specify the contents of element j which starts at 2, and your code blows up immediately because you're trying to say "for a list of 2 elements, please store the following value as the 3rd element".
Again, lists like the one in Python usually aren't that forgiving.
Instead, you're going to have to do one of two things:
In some cases, you want to store into an existing element, or add a new element, depending on whether the index you specify is available or not
In other cases, you always want to add a new element
In your case, you want to do nbr. 2, which means you want to rewrite this line of code:
a[j]=a[j-2]+(j+2)*(j+3)/2
to this:
a.append(a[j-2]+(j+2)*(j+3)/2)
This will append a new element to the end of the list, which is OK, instead of trying to assign a new value to element N+1, where N is the current length of the list, which isn't OK.
At j=2 you're trying to assign to a[2], which doesn't exist yet. You probably want to use append instead.
If you want to debug it, just change your code to print out the current index as you go:
a=[]
a.append(3)
a.append(7)
for j in range(2,23480):
print j # <-- this line
a[j]=a[j-2]+(j+2)*(j+3)/2
But you'll probably find that it errors out the second you access a[2] or higher; you've only added two values, but you're trying to access the 3rd and onward.
Try replacing your list ([]) with a dictionary ({}); that way, you can assign to whatever numbers you like -- or, if you really want a list, initialize it with 23479 items ([0] * 23479).
Python lists must be pre-initialzed. You need to do a = [0]*23480
Or you can append if you are adding one at a time. I think it would probably be faster to preallocate the array.
Python does not dynamically increase the size of an array when you assign to an element. You have to use a.append(element) to add an element onto the end, or a.insert(i, element) to insert the element at the position before i.