python list math index variable - python

This works the way I want
a = [1,8,10]
b = list([a])
a = [0,8,10]
b.append(a)
a = [0,0,10]
b.append(a)
print(b)
giving me the list that I want:
[[1, 8, 10], [0, 8, 10], [0, 0, 10]]
I need to change the values using variables based on the index of the list like this
a = [1,8,10]
b = list([a])
a[0] = a[0] - 1
b.append(a)
print(b)
and I get this result :
[[0, 8, 10], [0, 8, 10]]
My entire point is to keep track of my moves for creating the nim game. I think I see how setting a[0] = a[0] - 1 changes the value in both places even when I tried using deep copy but I am stumped on how else to get the answer. I am sure it is obvious but I don't know what key words to use to search for the solution, so please help me.

Using deepcopy should work -- I suspect you were just using it in the wrong place.
The danger of using a single list as a template, as you were doing with a is that if you mutate it, you could end up changing the lists you've already appended to b. One way to get around this problem is to always create a new copy of a whenever you want to change it.
import copy
b = []
a = [1,8,10]
b.append(a)
a2 = copy.deepcopy(a)
a2[0] = a2[0] - 1
b.append(a2)
print(b)
Another way might be to make a copy of a whenever you append it to b, so that you don't have to keep creating new variables:
import copy
b = []
a = [1,8,10]
b.append(copy.deepcopy(a))
a[0] = a[0] - 1
b.append(copy.deepcopy(a))
print(b)
The common point between these two different approaches is that we always append any given list exactly once. In your code, you append the same list multiple times to b. That means that whenever you change a, it appears as if you changed everything in b.
In the two examples I provided, I append a list only once, and copy it if I need to make changes. By doing so, I ensure that each list inside b is unique, and avoid running into the issue you encountered.
As a side note, another way to create a copy of a list is to do a2 = a[:]. The a[:] is telling Python to get a list slice of a starting from the beginning of the list to the end, essentially copying it. Note that this is a shallow copy, not a deep copy. However, since your lists contain only numbers, a shallow copy should work fine.

Related

Why does this code change only some elements of the list and not the others?

I don't understand why the result of the following code is [1,[2,5]] and not [3,[2,5]]. Why is the element in the sublist changed but the element outside of the sublist isn't?
I'm new to Python so maybe I don't see something which should be very obvious. I've read about deep and shallow copies, but it didn't help.
a = [1,[2,3]]
b = a[:]
a[0] = 3
a[1][1] = 5
print(b)
I created the list slice on line 2. But since it has no start or end values, the slice equals the entire list, right? Then why does 3 change to 5, but 1 stays the same?
Because, in Python, each list is an independent object.
You can do a deep copy using the module 'copy' to solve this specific problem.
import copy
a = [1,[2,3]]
b = copy.deepcopy(a)
a[0] = 3
a[1][1] = 5
print(b)
Result: [1, [2, 3]]

Variable assignment and manipulation in Python [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Why does a[0] change? [duplicate]
(1 answer)
Closed 7 years ago.
I am pretty confused with the difference in results of the Python codes below. Why in first case "a" does not change upon the change of "b", but in second one does?
a=b=[]
b = [1,2,3]
print b,a
########## compare with below ################################
a=b=[]
b.append([1,2,3])
print b,a
Result of first part is:
[1,2,3] [ ]
and result of the second part is:
[[1,2,3]] [[1,2,3]]
It was suggested that it is a duplicate question but I think here I am changing the list "b" with two different ways and I guess it could show how these two methods of variable manipulation could be different.
Because = is not the same as append.
When you do b = [1, 2, 3], you assign a new value to b. This does not involve the old value of b in any way; you can do this no matter what value b held before.
When you do b.append(...), you modify the object that is the existing value of b. If that object is also the value of other names (in this case, a), then those names will also "see" the change. Note that, unlike assignment, these types of operations depend on what kind of value you have. You can do b.append(...) because b is a list. If b was, say, an integer, you could not do b.append, but you could still do b = [1, 2, 3].
In the first example, you are reassigning the variable b, and now it points to another list.
a = b = [] # a -> [] <- b
b = [1, 2, 3] # a -> [], b -> [1, 2, 3]
In the second example, both a and b variables are pointing to the same list, and you are inserting values in the list:
a = b = [] # a -> [] <- b
b.append([1, 2, 3]) # a -> [[1, 2, 3]] <- b
To elaborate on the other answers, this is straight from the Python docs:
list.append(x)
Add an item to the end of the list; equivalent to a[len(a):] = [x].
Looking at:
a[len(a):] = [x]
it is easy to see that using append is modifying the original list (a in the python sample code, b in your case).
As the others people have pointed out, using an assignment statement is assigning a new value to b, instead of modifying it via append.

Is a Python list guaranteed to have its elements stay in the order they are inserted in?

If I have the following Python code
>>> x = []
>>> x = x + [1]
>>> x = x + [2]
>>> x = x + [3]
>>> x
[1, 2, 3]
Will x be guaranteed to always be [1,2,3], or are other orderings of the interim elements possible?
Yes, the order of elements in a python list is persistent.
In short, yes, the order is preserved. In long:
In general the following definitions will always apply to objects like lists:
A list is a collection of elements that can contain duplicate elements and has a defined order that generally does not change unless explicitly made to do so. stacks and queues are both types of lists that provide specific (often limited) behavior for adding and removing elements (stacks being LIFO, queues being FIFO). Lists are practical representations of, well, lists of things. A string can be thought of as a list of characters, as the order is important ("abc" != "bca") and duplicates in the content of the string are certainly permitted ("aaa" can exist and != "a").
A set is a collection of elements that cannot contain duplicates and has a non-definite order that may or may not change over time. Sets do not represent lists of things so much as they describe the extent of a certain selection of things. The internal structure of set, how its elements are stored relative to each other, is usually not meant to convey useful information. In some implementations, sets are always internally sorted; in others the ordering is simply undefined (usually depending on a hash function).
Collection is a generic term referring to any object used to store a (usually variable) number of other objects. Both lists and sets are a type of collection. Tuples and Arrays are normally not considered to be collections. Some languages consider maps (containers that describe associations between different objects) to be a type of collection as well.
This naming scheme holds true for all programming languages that I know of, including Python, C++, Java, C#, and Lisp (in which lists not keeping their order would be particularly catastrophic). If anyone knows of any where this is not the case, please just say so and I'll edit my answer. Note that specific implementations may use other names for these objects, such as vector in C++ and flex in ALGOL 68 (both lists; flex is technically just a re-sizable array).
If there is any confusion left in your case due to the specifics of how the + sign works here, just know that order is important for lists and unless there is very good reason to believe otherwise you can pretty much always safely assume that list operations preserve order. In this case, the + sign behaves much like it does for strings (which are really just lists of characters anyway): it takes the content of a list and places it behind the content of another.
If we have
list1 = [0, 1, 2, 3, 4]
list2 = [5, 6, 7, 8, 9]
Then
list1 + list2
Is the same as
[0, 1, 2, 3, 4] + [5, 6, 7, 8, 9]
Which evaluates to
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Much like
"abdcde" + "fghijk"
Produces
"abdcdefghijk"
You are confusing 'sets' and 'lists'. A set does not guarantee order, but lists do.
Sets are declared using curly brackets: {}. In contrast, lists are declared using square brackets: [].
mySet = {a, b, c, c}
Does not guarantee order, but list does:
myList = [a, b, c]
I suppose one thing that may be concerning you is whether or not the entries could change, so that the 2 becomes a different number, for instance. You can put your mind at ease here, because in Python, integers are immutable, meaning they cannot change after they are created.
Not everything in Python is immutable, though. For example, lists are mutable---they can change after being created. So for example, if you had a list of lists
>>> a = [[1], [2], [3]]
>>> a[0].append(7)
>>> a
[[1, 7], [2], [3]]
Here, I changed the first entry of a (I added 7 to it). One could imagine shuffling things around, and getting unexpected things here if you are not careful (and indeed, this does happen to everyone when they start programming in Python in some way or another; just search this site for "modifying a list while looping through it" to see dozens of examples).
It's also worth pointing out that x = x + [a] and x.append(a) are not the same thing. The second one mutates x, and the first one creates a new list and assigns it to x. To see the difference, try setting y = x before adding anything to x and trying each one, and look at the difference the two make to y.
Yes the list will remain as [1,2,3] unless you perform some other operation on it.
aList=[1,2,3]
i=0
for item in aList:
if i<2:
aList.remove(item)
i+=1
aList
[2]
The moral is when modifying a list in a loop driven by the list, takes two steps:
aList=[1,2,3]
i=0
for item in aList:
if i<2:
aList[i]="del"
i+=1
aList
['del', 'del', 3]
for i in range(2):
del aList[0]
aList
[3]
Yes lists and tuples are always ordered while dictionaries are not

Python: Change the parameter of the loop while the loop is running

I want to change a in the for-loop to [4,5,6].
This code just print: 1, 2, 3
a = [1,2,3]
for i in a:
global a
a = [4,5,6]
print i
I want the ouput 1, 4, 5, 6.
You'll need to clarify the question because there is no explanation of how you should derive the desired output 1, 4, 5, 6 when your input is [1, 2, 3]. The following produces the desired output, but it's completely ad-hoc and makes no sense:
i = 0
a = [1, 2, 3]
while i < len(a):
print(a[i])
if a[i] == 1:
a = [4, 5, 6]
i = 0 # edit - good catch larsmans
else:
i += 1
The main point is that you can't modify the parameters of a for loop while the loop is executing. From the python documentation:
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.
Edit: if based on the comments you are trying to walk URLs, you need more complicated logic to do a depth-first or breadth-first walk than just replacing one list (the top-level links) with another list (links in the first page). In your example you completely lose track of pages 2 and 3 after diving into page 1.
The issue is that the assignment
a = [4,5,6]
just changes the variable a, not the underlying object. There are various ways you could deal with this; one would be to use a while loop like
a = [1,2,3]
i = 0
while i<len(a):
print a[i]
a = [4,5,6]
i += 1
prints
1
5
6
If you print id(a) at useful points in your code you'll realise why this doesn't work.
Even something like this does not work:
a = [1,2,3]
def change_a(new_val):
a = new_val
for i in a:
change_a([4,5,6])
print i
I don't think it is possible to do what you want. Break out of the current loop and start a new one with your new value of a.

Python list + list vs. list.append()

Today I spent about 20 minutes trying to figure out why
this worked as expected:
users_stories_dict[a] = s + [b]
but this would have a None value:
users_stories_dict[a] = s.append(b)
Anyone know why the append function does not return the new list? I'm looking for some sort of sensible reason this decision was made; it looks like a Python novice gotcha to me right now.
append works by actually modifying a list, and so all the magic is in side-effects. Accordingly, the result returned by append is None. In other words, what one wants is:
s.append(b)
and then:
users_stories_dict[a] = s
But, you've already figured that much out. As to why it was done this way, while I don't really know, my guess is that it might have something to do with a 0 (or false) exit value indicating that an operation proceeded normally, and by returning None for functions whose role is to modify their arguments in-place you report that the modification succeeded.
But I agree that it would be nice if it returned the modified list back. At least, Python's behavior is consistent across all such functions.
The append() method returns a None, because it modifies the list it self by adding the object appended as an element, while the + operator concatenates the two lists and return the resulting list
eg:
a = [1,2,3,4,5]
b = [6,7,8,9,0]
print a+b # returns a list made by concatenating the lists a and b
>>> [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
print a.append(b) # Adds the list b as element at the end of the list a and returns None
>>> None
print a # the list a was modified during the last append call and has the list b as last element
>>> [1, 2, 3, 4, 5, [6, 7, 8, 9, 0]]
So as you can see the easiest way is just to add the two lists together as even if you append the list b to a using append() you will not get the result you want without additional work

Categories