Here is my code:
for each in range(0, number_of_trials):
temp_list = source_list
for i in range(10):
x = random.randrange(0, len(temp_list))
board[i] = temp_list[x]
del temp_list[x]
This code is deleting each element from temp_list, as would be expected. But temp_list is not being reset each time the initial for loop runs, setting it back to source_list. As a result, every delete from temp_list is permanent, lasting for every following iteration of the for loop. How can I avoid this and have temp_list "reset" back to its initial status each time?
The statement temp_list = source_list does not create a new list. It gives a new name temp_list to an existing list. It doesn't matter what name you use to access the list—any changes made via one name will be visible via another.
Instead, you need to copy the list, like this:
temp_list = source_list[:]
This creates a new list that starts with the same contents as source_list. Now you can change the new list without affecting the original.
>>> a = [ 1 ]
>>> b = a
>>> del a[0]
>>> print b
[]
Basically, when you use "=", both variables point to the same object. To make a copy, use the copy module.
Copy the list elements instead of the list reference.
temp_list = source_list[:]
This is because :
temp_list = source_list # Doesn't copies the list, but adds the reference.
So, each iteration you are refreshing the reference only.
To copy the list, you can use the trick [:]. This performs list slicing with nothing sliced and produces a new list exactly same as the list being sliced.
Therefore,
for each in range(0, number_of_trials):
temp_list = source_list[:] # Changed
for i in range(10):
x = random.randrange(0, len(temp_list))
board[i] = temp_list[x]
del temp_list[x]
This should work as expected. :)
Related
I have a propably very basic problem in Python. However, I would be very thankful, if someone could help me to understand, what is happening here:
My code is as follows:
purchaseprices = {'Stock_A': [[10, 4.21],[20, 5.23], [5, 8.32]],
'Stock_B': [[5, 8.23],[15, 7.42], [10, 7.53]]}
def update_purchaseprices(name, number_of_shares):
remaining_number_of_shares = number_of_shares
updated_purchaseprices = purchaseprices[name][:]
indices_to_delete = []
for i in range(len(updated_purchaseprices)):
if updated_purchaseprices[i][0] < remaining_number_of_shares:
remaining_number_of_shares -= updated_purchaseprices[i][0]
indices_to_delete.append(i)
else:
updated_purchaseprices[i][0] = updated_purchaseprices[i][0] - remaining_number_of_shares
break
updated_purchaseprices = [i for j, i in enumerate(updated_purchaseprices) if j not in indices_to_delete]
return updated_purchaseprices
name = "Stock_A"
number_of_shares = 34
print(purchaseprices['Stock_A'])
updated_purchaseprices = update_purchaseprices(name, number_of_shares)
print(updated_purchaseprices) # this works as expected
print(purchaseprices['Stock_A']) # why did the original list got changed as well?
Here is, what I wanted to do: I have an original list, which is stored in a dictionary called purchaseprices. This list can be accessed by purchaseprices['Stock_A’]. Now I tried to write a function to return a list called updated_purchaseprices, which is basically a modified version of the original list. In order to leave the original list unchanged, I made a copy of it by including updated_purchaseprices = purchaseprices[name]:. Unfortunately my code nevertheless also changes the original list. Can someone please tell me why this is happening?
As you probably know because you used [:], a list is mutable and you need to take a copy in your function. But the copy still contains the original objects (sublists).
You need to copy those too!
Replace:
updated_purchaseprices = purchaseprices[name][:]
with:
updated_purchaseprices = [l.copy() for l in purchaseprices[name]]
or:
import copy
updated_purchaseprices = copy.deepcopy(purchaseprices[name])
Why do pop and append not finish out the entire loop? My first guess was that pop didn't readjust the index of the original list, but that doesn't appear to be true when I print(txt[0]) to confirm it's still at the front. I'm trying to figure out why the below does not work. Thank you.
txt = 'shOrtCAKE'
txt = list(txt)
new_list = []
for x in txt:
value = txt.pop(0)
new_list.append(value)
print(new_list)
print(txt)
print(txt[0])
You shouldn't modify the list while iterating over it. Instead use this code
for x in txt:
value = x
new_list.append(value)
txt = [] # assuming you want txt to be empty for some reason
But then if you end up printing txt[0] you'll end up with error as the list index will be out of range
However you don't really need to be looping. Just do the following:
new_list = txt[:] # [:] ensures that any changes done to txt won't reflect in new_list
You should not remove elements from a list that you are iterating over. In this case, you are not even using the values of the list obtained during iteration.
There are various possibilities if you still want to use pop, which don't involve iterating over txt. For example:
Loop a fixed number of times (len(txt) computed at the start):
for _ in range(len(txt)):
new_list.append(txt.pop(0))
Loop while txt is not empty:
while txt:
new_list.append(txt.pop(0))
Loop until pop fails:
while True:
try:
new_list.append(txt.pop(0))
except IndexError:
break
Of course, you don't have to use pop. You could do this for example:
new_list.extend(txt) # add all the elements of the old list
txt.clear() # and then empty the old list
qtd_packs = 2
size_pack = 16
pasta = []
pasta.append ('packs/krun/')
pasta.append ('packs/parting2/')
for k in range(0, qtd_packs):
for n in range(1, size_pack+1):
samples_in.append (pasta[k]+str(n)+'.wav')
samples.append(samples_in)
del samples_in[0:len(samples_in)]
print(samples)
I'm basically trying to add the samples_in inside the samples list, then delete the old samples_in list to create a new one. This will happen 2 times, as the qtd_packs =2. But in the end, what I get is two empty lists:
[[], []]
I've append'ed the samples_in inside samples BEFORE deleting it. So what happened?
Thank you
In Python, lists are passed by reference. When you append samples_in to samples, Python appends a reference to samples_in to samples. If you want to append a copy of samples_in to samples, you can do:
samples.append(samples_in[:])
This effectively creates a new list from all the items in samples_in and passes that new list into samples.append(). So now when you clear the items in samples_in, you're not clearing the items in the list that was appended to samples as well.
Also, note that samples_in[:] is equivalent to samples_in[0:len(samples_in)].
The problem is that after this:
samples.append(samples_in)
The newly-appended value in samples is not a copy of samples_in, it's the exact same value. You can see this from the interactive interpreter:
>>> samples_in = [0]
>>> samples = []
>>> samples.append(samples_in)
>>> samples[-1] is samples_in
True
>>> id(samples[-1]), id(samples_in)
(12345678, 12345678)
Using an interactive visualizer might make it even easier to see what's happening.
So, when you modify the value through one name, like this:
>>> del samples_in[0:len(samples_in)]
The same modification is visible through both names:
>>> samples[-1]
[]
Once you realize that both names refer to the same value, that should be obvious.
As a side note, del samples_in[:] would do the exact same thing as del samples_in[0:len(samples_in)], because those are already the defaults for a slice.
What if you don't want the two names to refer to the same value? Then you have to explicitly make a copy.
The copy module has functions that can make a copy of (almost) anything, but many types have a simpler way to do it. For example, samples_in[:] asks for a new list, which copies the slice from 0 to the end (again, those are the defaults). So, if you'd done this:
>>> samples.append(samples_in[:])
… you would have a new value in samples[-1]. Again, you can test that easily:
>>> samples[-1], samples_in
([0], [0])
>>> samples[-1] == samples_in
True
>>> samples[-1] is samples_in
False
>>> id(samples[-1]), id(samples_in)
23456789, 12345678
And if you change one value, that doesn't affect the other—after all, they're separate values:
>>> del samples_in[:]
>>> samples[-1], samples_in
([0], [])
However, in this case, you really don't even need to make a copy. The only reason you're having a problem is that you're trying to reuse samples_in over and over. There's no reason to do that, and if you just created a new samples_in value each time, the problem wouldn't have come up in the first place. Instead of this:
samples_in = []
for k in range(0, qtd_packs):
for n in range(1, size_pack+1):
samples_in.append (pasta[k]+str(n)+'.wav')
samples.append(samples_in)
del samples_in[0:len(samples_in)]
Do this:
for k in range(0, qtd_packs):
samples_in = []
for n in range(1, size_pack+1):
samples_in.append (pasta[k]+str(n)+'.wav')
samples.append(samples_in)
beetea's answer below offers the solution if you want samples to contain two lists, each of which have the strings for one of your two qtd_packs:
qtd_packs = 2
size_pack = 16
pasta = []
pasta.append ('packs/krun/')
pasta.append ('packs/parting2/')
samples = []
samples_in = []
for k in range(0, qtd_packs):
for n in range(1, size_pack+1):
samples_in.append (pasta[k]+str(n)+'.wav')
samples.append(samples_in[:])
del samples_in[0:len(samples_in)]
print(samples)
produces this output:
[['packs/krun/1.wav', 'packs/krun/2.wav', 'packs/krun/3.wav', 'packs/krun/4.wav',
'packs/krun/5.wav', 'packs/krun/6.wav', 'packs/krun/7.wav', 'packs/krun/8.wav',
'packs/krun/9.wav', 'packs/krun/10.wav', 'packs/krun/11.wav', 'packs/krun/12.wav',
'packs/krun/13.wav', 'packs/krun/14.wav', 'packs/krun/15.wav', 'packs/krun/16.wav'],
['packs/parting2/1.wav', 'packs/parting2/2.wav', 'packs/parting2/3.wav',
'packs/parting2/4.wav', 'packs/parting2/5.wav', 'packs/parting2/6.wav',
'packs/parting2/7.wav', 'packs/parting2/8.wav', 'packs/parting2/9.wav',
'packs/parting2/10.wav', 'packs/parting2/11.wav', 'packs/parting2/12.wav',
'packs/parting2/13.wav', 'packs/parting2/14.wav', 'packs/parting2/15.wav',
'packs/parting2/16.wav']]
Now, when I originally read your question, I thought you were trying to make a single list containing all the strings. In that instance, you could use
samples.extend(samples_in)
instead of
samples.append(samples_in[:])
and you would get a flat list containing only the strings.
Let's say I have a list, L = [a,b,c,d], and a copy of this list, and also a for-loop that has a recursion code in it:
for item in L:
if:
*some base code*
Lcopy.remove(item)
L = []
L += Lcopy[:]
else:
*some recursion code*
return ...
But after the every recursion is done, L goes back to how it was originally. I know that once the code goes into the recursion, Python gives a new memory address to the list (L) that it uses, but is it possible to make the original L, the very first L, to update and get rid of the values that was was supposed to be deleted?
The problem is in L = []
This is the moment after L is pointing to another value, a newly created list.
Python doesn't do anything special with references in recursion. Lists are always passed by reference. Assignment breaks the reference of L to the old list.
When you have L = [] you're re-assigning that function's local name L to a completely new list. If you instead want to empty out the same list, you need to delete all of its contents, like so: del L[:]
For a more detailed explanation of Python's execution model, and what assigning to a variable actually does, check out this blog post by Jeff Knupp.
I'm stunned with this function I've written for python. I've observed that in the lower while it changes the values in the list vctor even though that list is not touched along the function. I've passed the pair (10, [1,3,5,7,10]) and it has changed the list vctor to [1,3,5,8,10]. Is there an explanation for this?
def siguiente(k,vctor):
l = len(vctor)
vctorsig = vctor
i = l-1
while i>= 0:
if vctorsig[i] <= k - l + i:
j=i
while j<=l-1:
print vctor
vctorsig[j] = vctor[i]+j-i+1
j=j+1
i = -1
else:
i = i-1
return vctorsig
When you do vctorsig = vctor, you are making vctorsig a reference to the list referenced by vctor, so when you modify it, you modify the original list.
If you wish to copy the list there, you can simply do vctorsig = list(vctor).
It's a little hard to tell because your indentation is funny, but I think that the line:
vctorsig = vctor
is your problem. In this line, you create a new reference to the same list. In other words, if you change vctorsig (in this line vctorsig[j] = vctor[i]+j-i+1), you also change vctor since they are the same list. The easy way out of this is to make a copy:
vctorsig = vctor[:]