Manipulating Python Lists - python

I have a list of 100 elements. I am trying to create a function that will make 300 copies of that list and then store those copies into a blank list. I then need the function to choose an indexed value at random from each copied list. So, it might choose the 25th index value in the first copied list, and then it might choose the 60th index value in the next copied list. Then, the index of the value is an argument of a pre-defined function. The problem is that my copied lists are not being manipulated.
my code is as follows:
def condition_manipulate(value):
list_set=[] #this is the list in which the copied lists will go
for i in range(0,value):
new_list=initial_conditions[:] #initial_conditions is the list to be copied
list_set.append(new_list)
for i in list_set: #My confusion is here. I need the function to choose
for j in i: #A random value in each copied list that resides
x=random.choice(i) #In list_set and then run a predefined function on it.
variable=new_sum(i.index(x)
i[i.index(x)]=variable
return list_set
#running condition_manipulate(300) should give me a list with 300 copies of a list
#Where a random value in each list is manipulated by the function new_sum
I have tried almost everything. What am I doing wrong? Any Help will be appreciated. Thanks.

Try:
import random
def condition_manipulate(value):
list_set=[]
for i in range(value):
new_list=initial_conditions[:]
i=random.choice(range(len(initial_conditions)))
new_list[i]=new_sum(new_list[i])
list_set.append(new_list)
return list_set

If you really need copies of lists rather than shallow copies then you need to:
import copy
oldlist = [.....]
newlist = copy.deepcopy(oldlist)
Otherwise all the copies are really the same list.>>> o = [1, 2, 3]
>>> n = o
>>> n.append(4)
>>> o
[1, 2, 3, 4]
>>> n = copy.deepcopy(o)
>>> n
[1, 2, 3, 4]
>>> n.append(5)
>>> n
[1, 2, 3, 4, 5]
>>> o
[1, 2, 3, 4]
>>>

Related

Mysterious duplicate arrays in Python

I am trying to understand why the first for loop does not return what the second for loop is returning. Can anyone explain this clearly to me? My searching did not unearth any results since I don't know what this problem is called.
arr = [1,2,3]
tempArr = []
res = []
for num in range(0,3):
tempArr.append(arr[num])
res.append(tempArr)
print(tempArr, res)
print()
tempArr = []
res = []
for num in range(0,3):
tempArr.append(arr[num])
res.append(list(tempArr))
print(tempArr, res)
Returns:
[1] [[1]]
[1, 2] [[1, 2], [1, 2]]
[1, 2, 3] [[1, 2, 3], [1, 2, 3], [1, 2, 3]]
[1] [[1]]
[1, 2] [[1], [1, 2]]
[1, 2, 3] [[1], [1, 2], [1, 2, 3]]
Lists in Python are mutable sequences. This means that you can modify the elements of a list once it is created.
You are creating a list and assigning it to the variable 'tempArr'. Then in the first loop you are appending 'tempArr' to the 'res' list.
Note that because lists are mutable, you are never changing what 'tempArr' is, you only modify its content, so you are adding three times the same list to 'res'. When you modify the 'tempArr' list, you modify all the lists inside 'res' (again, because they are the same list)
An explicit example you can play with is the following:
# Create a new list
tempArr = []
# Create a list containing the initial one (which is empty)
res = [tempArr]
# Now, lets modify the 'tempArr'
tempArr.append("This wasn't here before")
# Make your prediction on what will happen now:
print(res)
Another thing we can do is play with the 'is' comparison, in your code:
arr = [1,2,3]
tempArr = []
res = []
for num in range(0,3):
tempArr.append(arr[num])
res.append(tempArr)
# Check if the element we have appended into 'res' is the 'tempArr' list. The result is always True.
print(tempArr is res[-1])
print(tempArr, res)
# Let's compare the three elements of the 'res' list and check if they are the same list, we see that they are.
print(res[0] is res[1] is res[2])
On the other hand, in the second loop, you are not appending the 'tempArr' list into 'res', you are first creating a new list by calling "list(tempArr)", and then appending this new list into 'res'. Now we can play a little bit with this:
tempArr = []
res = []
for num in range(0,3):
tempArr.append(arr[num])
res.append(list(tempArr))
# Check if the element we have appended into 'res' is the 'tempArr' list.
print(tempArr is res[-1])
# This time the result is False. So we are not appending 'tempArr', but a new list with the same elements.
print(tempArr, res)
# Let's compare again the three elements of the 'res' list and see if they are the same elements:
print(res[0] is res[1] is res[2])
As a consequence, because in the second loop we are creating new lists, when you modify the initial one, this doesn't affect the elements inside the 'res' list.
list(...) makes a copy. Without making a copy, the same reference is appended, thus subsequent changes show up later in earlier elements as well.
To see the references, do a print(list(map(id, res))). If the printed number is the same, then it's the same list object.
Because we use list() to make shallow copy
This means list(tempArr) will now be a new and independent object with the same contents as tempArr

Lists, how to add multiple values at one time

i just wondered if there is a way to append at one time multiple values i.e.
defining an function with the parameter x, that will automaticly append the amount of elements definied by an x.
def Append(x):
L = []
L.append(x - Elements)
return L
Thanks in advance
Try this to append several similar values to an existing list:
>>> l = [1,2]
>>> l += [3]*2
>>> l
[1, 2, 3, 3]
.extend() list method works too
>>> l = [1,2]
>>> l.extend([3]*2)
>>> l
[1, 2, 3, 3]
i meant it to add an x-Amount of Elements, not an specific one but just for example: Append(20) -> Should add 20 new elements

How to properly remove elements from array in loop using Python

I tried to remove only one element from an array and print remaining ones in a loop:
arr = [1,2,3,4,5]
for i in arr:
a = arr
a.remove(i)
print a
So I am expecting it to print this:
[2, 3, 4, 5]
[1, 3, 4, 5]
[1, 2, 3, 5]
[1, 2, 3, 4]
Why am I gettting the following results instead:
[2, 3, 4, 5]
[2, 4, 5]
[2, 4]
This is a classic problem of deep vs shallow copy.
Python copies the array by reference. So, any changes to the new variable (a in your case) will be reflected in the main array (arr). Removing element from a also remove elements from arr.
You need to use following for creating a copy.
a = arr[:]
This will not remove any elements from arr.
You've already got explanations, I'll provide an alternative - you can produce requested output without using remove at all:
arr = [1,2,3,4,5]
for i in arr:
a = [x for x in arr if x != i]
print a
(beware of non-unique elements in arr, if there are any, both this code and yours will produce unexpected results, though in different ways).
You can try this.
arr = [1, 2, 3, 4, 5, 6, 7 ]
for index, item in enumerate(arr):
print(arr[0:index] + arr[index+1:])
I think this can help you.
If you don't have any repeated value you can use this too.
for item in arr:
print(set(arr) - set([item]))
Python lists are mutable i.e. modifying operations (like list.remove()) on them do not produce a new list but modify the existing list instead so each your cycle actually permanently modifies the source list and elements are lost. You'd need to copy your whole list each time you want to modify it in order to achieve what you want, or you can create a new list with elements excluded, or, for very long lists, reconstructing by slicing is probably the most performant way:
arr = [1,2,3,4,5]
for i in range(len(arr)):
a = arr[0:i] + arr[i+1:]
print(a)

Python: identical items in list are treated as the same

I have a nested list in python. Each item the second list is also a nested list. My goal is to duplicate one list, insert it right at the same index, and then modify each one. So, example of start condition:
myList = [[first_list], [[element_1], [element_2, element_3], [duplicate_me]]]
Duplication/insertion at myList[1][2]:
myList = [[first_list], [[element_1], [element_2, element_3], [duplicate_me], [duplicate_me]]]
This all works fine. However, when I run the append code:
myList[1][2].append(new_element)
It appends the new element to both duplicates, like this:
myList = [[first_list], [[element_1], [element_2, element_3], [duplicate_me, new_element], [duplicate_me, new_element]]]
Is there something bizarre going on in the way the elements are called or indexed? I see a potential workaround (calling the item to be duplicated to a working variable, modifying it there, and then inserting it at the same point), but that seems needlessly complex.
Thanks!
myList[1][2] and myList[1][3] don't just have the same values, they are actually the same list. You are looking at the same area in memory when you read both of them. So, when you change one, you are changing the other, because both are actually the exact same thing! Instead doing what you do to duplicate the list, you should make a copy of it.
Here's an example of the problem from a python shell:
>>> mylist = [1, 2, 3]
>>> newlist = mylist
>>> newlist.append(4)
>>> newlist
[1, 2, 3, 4]
>>> mylist
[1, 2, 3, 4]
A common way to fix this is to use one of these tricks:
>>> mylist = [1, 2, 3]
>>> newlist = mylist[:] # OR :
>>> newlist = [x for x in mylist]
>>> newlist.append(4)
>>> newlist
[1, 2, 3, 4]
>>> mylist
[1, 2, 3]
The second and third lines will create a copy of the list. I tend to combine the two like this, if I need to copy a 2D list:
>>> newlist = [x[:] for x in mylist]
Use one of these to create your duplicate, and all will be well again.
You are most likely not duplicating the target list (*[duplicate_me]*), but rather simply appending a duplicated reference to the same list into myList.
You need to copy the list before adding it to myList. One simple way is to call the list constructor passing in the original [duplicate_me]

Python index usage

Here is some code:
# Question 9: Deep Reverse
# Define a procedure, deep_reverse, that takes as input a list,
# and returns a new list that is the deep reverse of the input list.
# This means it reverses all the elements in the list, and if any
# of those elements are lists themselves, reverses all the elements
# in the inner list, all the way down.
# Note: The procedure must not change the input list.
# The procedure is_list below is from Homework 6. It returns True if
# p is a list and False if it is not.
def is_list(p):
return isinstance(p, list)
#For example,
def deep_reverse(n):
n.reverse()
for entry in n:
if is_list(entry):
entry.reverse()
deep_reverseA(entry)
return n
def deep_reverseA(n):
for entry in n:
if is_list(entry):
entry.reverse()
deep_reverseA(entry)
return n
p = [1, [2, 3, [4, [5, 6]]]]
print deep_reverse(p)
#>>> [[[[6, 5], 4], 3, 2], 1]
print p
#>>> [1, [2, 3, [4, [5, 6]]]]
q = [1, [2,3], 4, [5,6]]
print deep_reverse(q)
#>>> [ [6,5], 4, [3, 2], 1]
print q
#>>> [1, [2,3], 4, [5,6]]
My problem is that once I run the code the values of p and q change. How can I make them not change. I know that in python indexes are connected so if indexA = indexB and you change indexA then indexB will change. That is the problem I am having with fixing this problem.
I'll just tell you the answer right here, right now, with an explanation.
In python, variables are merely pointers to stored objects. So as you said in your post, if you declare foo = bar then foo not only is equal to bar, but foo is bar. This won't change unless you explicitly say so (for example you set bar = 2). So you need a way to make a copy of the original list.
There's this thing in python called list slicing, and I'm sure you heard of it. Basically you can get a portion of the list from indexA to indexB with my_list[indexA:indexB].
But you can also leave these spaces blank. indexA if not specified defaults to 0, and indexB defaults to -1 (the last element of the list).
So my_list[2:] returns all the elements from my_list[2] to my_list[-1]. Likewise, my_list[:3] returns my_list[0] to my_list[3].
Therefore, calling my_list[:] returns an exact copy of my_list, but not the actual list itself. This is what you need to do.
So applying it to your code:
def deep_reverse(n):
ncopy = n[:] #this is the part you need
#rest of function, replace `n` with `ncopy`
return ncopy
Also, do not apply this to deep_reverseA because in that function you are changing the original list in the copied list. You aren't changing the list you input into deep_reverse. If you did apply this to deep_reverseA, the lists wouldn't actually change (you would be returning a reverse of the copy but not the original)

Categories