Having trouble with printing mutated variable outside function (Python) [duplicate] - python

This question already has answers here:
having trouble with lists in python
(5 answers)
Closed 7 years ago.
def satisfiesF(L):
"""
Assumes L is a list of strings
Assume function f is already defined for you and it maps a string to a Boolean
Mutates L such that it contains all of the strings, s, originally in L such
that f(s) returns True, and no other elements
Returns the length of L after mutation
"""
result = []
for l in L:
result.extend(l)
L = list(result)
for i in result:
if i != 'a':
L.remove(i)
return len(L)
Basically what I am trying to do is mutate the list, L within the function. From my testing, it appears that the end result of L is exactly what I am looking for it to be, but when I print L outside of the function it just spits out the original, unmutated list. Can anyone help me fix this issue?
disclaimer: This is a homework problem, but I'm not looking for a solution to the whole problem - just this one issue. Thanks!

You are changing the name L to point to a new list inside the function, in line -
L = list(result)
This does not change the list outside the function, because only the local variable L changed to point to a new list, its previous reference was not changed (And the name/variable outside the function, that was used to call this function still points to the old list).
You should iterate over copy of result (created using result[:]) and remove from result , without changing the reference L points to. And then at end use L[:] = result , to make changes to the list reference that L points to.
Example -
list1 = ['a','b','c','d','e','f']
def satisfiesF(L):
result = []
for l in L:
result.extend(l)
for i in result[:]:
if i != 'a':
result.remove(i)
L[:] = result
return len(L)
satisfiesF(list1)
>>> 1
list1
>>> ['a']

def satisfiesF(L):
temp=L[:]
for x in temp:
if f(x)!=True:
L.remove(x)
return len(L)
def f(s):
return 'a' in s

replace
result = []
for l in L:
result.extend(l)
with
result =L[:]

Related

For loop didn't continue [duplicate]

This question already has answers here:
Remove all occurrences of a value from a list?
(26 answers)
Closed 1 year ago.
I want to remove the select element in sequence.
For example, I want to remove all 2 in sequence [1,2,3,2,3]
my code is
def remove_all(a_list, element):
for i in range(len(a_list)):
if element == a_list[i]:
a_list.remove(element)
return a_list
The output should be [1,3,3]
but the output of my code is [1,3,2,3]
I remove the first 2 but somehow the loop didn't go further to remove second 2. I wonder where is the problem of my code
Removing items in-place will almost certainly results in index errors.
[x for x in l if x != elem]
2 things.
You are modifying a list during iteration, I linked to a good read in my comment. also here
You return in the loop thus it stops at the return. Unindent the return, python is all about indentation unlike many other popular languages in this matter.
Try instead
Building another list for return:
def remove_all(a_list, element):
result = []
for ele in a_list:
if element != ele:
result.append(ele)
return result
Using a comprehension:
def remove_all(a_list, element):
return [ele for ele in a_list if ele != element]
a possible work-around is:
while element in a_list:
a_list.remove(element)
return element
But list comprehension works too, possibly even faster.
You should place the return after the loop finishes, something like:
def remove_all(a_list, element):
for i in a_list:
if element == i:
a_list.remove(element)
return a_list
a_list = [1, 2, 3, 2, 3]
result = remove_all(a_list, 2)
print(result)
Edit:
The code above does not work with the [2,2] case as pointed out in the comments.
Another solution would be:
myList = [2,2]
myList = list(filter((2).__ne__, myList))
print(myList)
Like that you don't copy the list anywhere, just is the list you are working on avoiding a list copy that can be expensive.
The __ne__ function checks that the element exists in the list returning True or False.

How is `var[:] = []` different from `var = []`? [duplicate]

This question already has answers here:
What is the correct way to reassign a list in Python?
(2 answers)
Understanding slicing
(38 answers)
Closed 3 years ago.
I normally understand how slices behave to the left and right of the assignment operator.
However, I've seen this in the Python (3.8.0) manual and trying to figure out what I'm missing.
clear the list by replacing all the elements with an empty list
letters[:] = []
How's that different from just letters = []?
(It's not easy to search for [:] as stackoverflow thinks you're looking for a tag. So, if there is already an answer I couldn't locate it.)
I see some rather irrelevant answers. So, to hopefully clarity, the question is not about what the [:] slice means, rather about assigning the empty list to one.
The assignment var = [] binds the name var to the newly created list. The name var may or may not have been previously bound to any other list, and if it has, that list will remain unchanged.
On the other hand, var[:] = [] expects var to be already bound to a list, and that list is changed in-place.
That's why the behaviour in these two cases is different:
var1 = [1, 2, 3]
var2 = var1
var1 = []
print(var1, var2) # prints [] [1, 2, 3]
var1 = [1, 2, 3]
var2 = var1
var1[:] = []
print(var1, var2) # prints [] []
This code demonstrates what is going on:
original = ['a','b','c']
letters = original
print('Same List')
print(original)
print(letters)
letters = []
print('Different lists')
print(original)
print(letters)
letters = original
letters[:] = []
print('Same list, but empty')
print(original)
print(letters)
Output:
Same List
['a', 'b', 'c']
['a', 'b', 'c']
Different lists
['a', 'b', 'c']
[]
Same list, but empty
[]
[]
The first part of the code: letters = original means that both variables refer to the same list.
The second part: letters = [] shows that the two variables now refer to different lists.
The third part: letters = original; letters[:] = [] starts with both variables referring to the same list again, but then the list itself is modified (using [:]) and both variables still refer to the same, but now modified list.
var = [] is an assignment to the name var. It replaces what, if anything, var used to refer to with [].
var[:] = [] is a method call in disguise: var.__setitem__(slice(), []). It replaces the elements referred to by the slice (in this case, all of them) with the elements in [], effectively emptying the list without replacing it altogether.
Incidentally, you can use var.clear() to accomplish the same thing; slice assignment more generally lets you replace one range of values with another, possibly longer or shorter, range of values.

Appending an empty list with list in recursive function

def permute(nums):
result = []
get_permute([], nums, result)
return result
def get_permute(current, num, result):
if not num:
result.append(current+[])
for i, v in enumerate(num):
current.append(num[i])
get_permute(current, num[:i] + num[i + 1:], result)
current.pop()
if __name__ == "__main__":
r = permute([1,2,3])
for perm in r:
print(perm)
What does current + [] do in result.append(current+[]) if I remove +[] it printing blank lists.
It's making a copy of the list. When you remove it, you run into the List of lists changes reflected across sublists unexpectedly problem, because the outer list contains many references to the same list, instead of references to many different lists.
You should be able to replace it with current.copy() (using Python >= 3.3) or list(current) to avoid similar confusion among future readers. (There are a lot of ways to copy a list. Pick the one you like and stick with it.)
What does the + [] do?
It generates a new list with the same contents as the old list.
>>> x = [1]
>>> id(x) == id(x + [])
False
>>> x == x + []
True
Why do I need this?
Whitout adding copies to your result, you would have the same list many times in your result and everytime you update that list, it affects your result.
>>> x = [1, 2]
>>> result = []
>>> result.append(x)
>>> x.append(3)
>>> result.append(x)
>>> result
[[1, 2, 3], [1, 2, 3]]
Some possible ways to make the could more readable would be
result.append(current[:])
or
result.append(list(current))
Why does it return blank lists if you remove the + []?
Because if you do not append copies to the result, there would be just one list in the result but multiple times. And you call .append(num[i]) on this list just as often as .pop(), which results in that list be empty.

Why does a loop through a list of lists not recognise, that a list is a copy

I encountered a (in my opinion) extremely strange behavior, when looping through a list of lists. It is very difficult to explain, but here is an example code:
k = [[0],[1],[2]]
for lis in k:
lis_copy = lis
lis_copy.append(0)
print lis
When executing this, I get:
[0, 0]
[1, 0]
[2, 0]
This is very strange for me, as the list which is appended is a copy of lis,
but lis is appended as well. I would assume this list to be untouched.
For example doing the same with a list of integers the following happens:
k = [0,1,2]
for num in k:
num_copy = num
num_copy = 0
print num
Output:
0
1
2
Just as expected num is not touched by the manipulation of num_copy.
If somebody could explain why this is happening and how to avoid this,
like how to disconnect the lis_copy from is, that would be great.
Wow, I am amazed I did not encounter mayor problems before, without knowing this. I think I should review quiet some of my code. Anyway I thought this is somehow connected to the loop, this seems not to be the case, therefore I think the best explanation can be found here:
How to clone or copy a list?
This is because Python lists (and dicts) are not copied to a new list, but the new list becomes a reference to that list. if you truly want to copy the list, use deepcopy
You could use copy.copy() or copy.deepcopy()to avoid this behavior:
import copy
k = [[0],[1],[2]]
for lis in k:
lis_copy = copy.copy(lis)
lis_copy.append(0)
print lis
Output:
[0]
[1]
[2]
Source: https://docs.python.org/2/library/copy.html
Case a:
k = [[0],[1],[2]]
for lis in k:
lis_copy = lis
lis_copy.append(0)
print lis
We have a pointer to a list, and inside the loop we have another pointer made that points to the inner list objects. Then a zero is appended to each object.
Case b:
k = [0,1,2]
for num in k:
num_copy = num
num_copy = 0
print num
We have a pointer to a list, and inside the loop we have another pointer made that points to the inner integers. The difference is that in this case the pointer is changed to then point to a zero object rather than the list elements.

How to cycle through items in an list and have each item get fed into a function [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Python: For each list element apply a function across the list
for example, let's say I have an array or list
myList = [a,b,c,d]
and I have a function that generates a random number.
How do I go through the list and have each of the
item in that list receives the random number generated by the
function and be added to the item?
So, say 'a' is the 1st in the list, 'a' goes into the function where a random number (let's say 5), is generated and adds itself to 'a' the result should be `[a+5, b+.......].
You use a list comprehension:
[func(elem) for elem in lst]
For your specific example, you can use an expression that sums the values:
[elem + func() for elem in myList]
where func() returns your random number.
Use map() function, that apply function to every item of iterable and return a list of the results:
def myfunc(x):
return x ** 2
>>> map(func, [1,2,3])
[1, 4, 9]
If you need one liner :-)
myList = [1,2,3,4]
[ i + map(lambda i: random.randint(10,20), myList)[index] for index, i in enumerate(myList) ]
I assume you're talking about integers. This little script should do what you want:
import random
def gen_rand(number):
generated = random.randint(1, 10) # you can specify whatever range you want
print generated
return number + generated
myList = [1,2,3,4,5]
print str(myList)
myList = [gen_rand(item) for item in myList]
print str(myList)
Or you could use the map function instead of the for loop.
Replace
myList = [gen_rand(item) for item in myList]
with
myList = map(gen_rand,myList)

Categories