python:two programs to delete val from nums - python

write a python program to delete val from array:
the first program is:
class Solution(object):
def removeElement(self,nums,val):
for x in nums:
if x == val:
nums.remove(val)
return len(nums)
when the nums is [3,3], the val is 3, the output is :1
the second program is :
class Solution(object):
def removeElement(self,nums,val):
while val in nums:
nums.remove(val)
return len(nums)
the nums is [3,3],the val is 3,the output is :0
could you please tell me the difference and reason

Python has a hard time iterating through something that is being changed during the iteration. It might fail or return unexpected results or never exit the iteration.
Because a container doesn't even keep track of iterators that are out
on it, much less hook even altering-method to loop over every such
iterator and somehow magically let each iterator know about the
alterations. It would be a lot subtle, complex code, and checks
slowing down very frequent operations.
nums=[3,4]
val=3
for x in nums:
print(x,nums)
if x > val:
nums.append(4)
The above code will not exit the iteration.So the correct way is to use a list comprehension to create a new list containing only the elements you don't want to remove:
print([i for i in nums if i!=val])
Or in-place alteration:
nums[:] = [i for i in nums if i!=val]
Hope this helps.

In the first example you are deleting an element inside the list while iterating over the elements of the list. That's a problem because you will run out of iterations after the first remove.
If the list is, for example, l = [1, 1, 2, 2] and you call removeElement(l, 2) after the first 2 is deleted, the length of l will be 3 and there won't be any iterations left (the list will be [1, 1, 2] and you will be at iteration number 3, that's why the loop stops and you get returned [1, 1, 2]).
In the second case, the while statement is: while there is still a 2 in the list, continue removing 2 from the list. This way, after the first iteration the l will look like [1, 1, 2] and there would still be a 2 inside it, so the loop continues and you get [1, 1].
You can apply this example on your case with l = [3, 3] and see if you understand it.
Hope that helped :)

Related

Unable to generate combination of numbers in python list using recursion

I am trying to generate a combination of numbers in python list using recursion
and my code is as follows
nums = [2,3,4,6]
def backtrck(temp, starting_index, nums):
if len(temp) == 2:
print(temp)
return
temp.append(nums[starting_index])
for i in range(starting_index + 1, len(nums)):
backtrck(temp, i, nums)
backtrck([], 0, nums)
for some reason, the above code is unable to generate the proper combinations.
Aim of the code: I want to generate all the combination of numbers starting with index 0 whose length should be equal to 2
expected output
[2, 3]
[2, 4]
[2, 6]
actual output
[2, 3]
[2, 3]
[2, 3]
[2, 3]
I don't understand what is going wrong with this recursion, I am hoping that someone could help me figure this out
Recursion is unnecessary when you can simply use for loop:
nums = [2,3,4,6]
def backtrck(starting_index, nums):
start = nums[starting_index]
for num in nums[starting_index + 1:]:
print([start, num])
backtrck(0, nums)
Output:
[2, 3]
[2, 4]
[2, 6]
where the slice nums[start_index + 1:] returns a list of all the elements of the nums list starting from one indice after the starting_index.
UPDATE
Since you've pointed out that the recursion was necessary in your code, simply replace the backtrck(temp, i, nums) recursive call with backtrck(i, nums, [temp[0], nums[i]]) to keep the starting index of the list:
nums = [2, 3, 4, 6]
def backtrck(starting_index, nums, temp=[]):
if len(temp) == 2:
print(temp)
return
temp.append(nums[starting_index])
for i in range(starting_index + 1, len(nums)):
backtrck(i, nums, [temp[0], nums[i]])
backtrck(0, nums)
Output:
[2, 3]
[2, 4]
[2, 6]
Note that I've changed the positional argument temp into a keyword argument. It will still work with temp as a positional argument, but it will be less practical if the temp list always starts out as empty.
What is wrong with your function:
After couple of recursive calls temp becomes [2,3] then on the next recursion your base case is met (len(temp) == 2:) and that instance of the function returns without adding anything. The next for loop iteration recurses and the same thing happens. Once temp is [2,3] it can never change.
How to fix it:
There are a number of problems with the structure of your function and it is not a simple one-line-fix. You need to figure out how to
when the base case is met
capture (or print) temp
return something meaningful to the previous function that it can use to continue making combinations
the function needs to act upon the return value from the recursive call
adding a for loop to a recursive procedure/process complicates things, maybe figure out how to do without it.
I would start over with the function. I don't know if you are asking someone to give you a completely new function so I'm going to search for questions regarding recursive solutions to find/generate list item combinations.
Here are some related SO Questions/Answers. If any of them solve your problem let us know so we can mark yours as a duplicate. Most don't have the taken two-at-a-time constraint but maybe you can adapt. there are many more.
Recursive function that returns combinations of size n chosen from list
Recursively find all combinations of list
python recursion list combinations without using generator
Using recursion to create a list combination
Loosely related:
Nth Combination
Finding all possible combinations of numbers to reach a given sum
Creating all possible k combinations of n items in C++ - not Python but algorithms might be useful.
When it comes to recursion, my advice is keep it simple and let the recursion do the work for you:
def backtrck(numbers):
if len(numbers) < 2:
return []
first, second, *rest = numbers
return [[first, second]] + backtrck([first] + rest)
nums = [2, 3, 4, 6]
print(*backtrck(nums), sep='\n')
OUTPUT
> python3 test.py
[2, 3]
[2, 4]
[2, 6]
>

Recursively defining a list in python, all in the list are replaced by the last item

I've just started working with Python, and I just came across some behavior that I don't understand. I've searched the site for an explanation, but I haven't been able to find it. Perhaps I don't know the right keywords to search.
I (think I)'m trying to define a list recursively, but in stead of repeatedly appending a new item to the list, all items in the list get replaced by this new item. See the snippet below. The code is supposed to generate a list I containing all (ordered) sublists of [0,...,n] of length d.
n = 5
d = 2
def next(S):
m = S.index(min([s for s in S if s+1 not in S]))
for i in range(m):
S[i] = i
S[m] += 1
return S
I = [[i for i in range(d)]]
while I[-1][0] <= n-d:
I += [next(I[-1])]
print(I)
I expected this to return the following list:
[[0,1],[0,2],[1,2],[0,3],[1,3],[2,3],[0,4],[1,4],[2,4],[3,4],[0,5],[1,5],[2,5],[3,5],[4,5]]
But in stead it returns the following list:
[[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5]]
Can anyone point me to an explanation as to why this code does not do what I expect it to? Thanks in advance.
Each call to next should get its own copy of the list; for example
I += [next(I[-1][:])]
Your code was building a list with multiple references to the same list. By sending each call to next its own copy, all of the elements in the result are distinct.
This could also have been accomplished by changing next to build a new list from scratch instead of modifying the list it is passed.
Your function next() alters the list it is given in-place, instead of creating a new copy. This is why all items in I are actually just the same list.
A statement like S = list(S) in next() would be sufficient to replace S with a (shallow) copy and ensure that changes to it are not applied to the original list.
You're passing a reference to an existing list rather than a copy of the list, so the list is modified as you iterate. The following might help explain this behavior:
def modify(li, i=3):
print(li)
li += [i] # This adds to the passed list
if i > 0:
modify(li, i-1)
def modify_copy(li, i=3):
print(li)
li = li + [i] # This overwrites "li" on every call
if i > 0:
modify_copy(li, i-1)
one = [4]
modify(one)
print("Result:", one)
two = [4]
modify_copy(two)
print("Result:", two)
Output
[4]
[4, 3]
[4, 3, 2]
[4, 3, 2, 1]
Result: [4, 3, 2, 1, 0]
[4]
[4, 3]
[4, 3, 2]
[4, 3, 2, 1]
Result: [4]

Logic works halfway but not completely

I am trying to remove duplicates from a sorted list.
nums = [0,0,1,1,1,2,2,3,3,4]
for i in range(len(nums)):
a = nums.count(i)
if(a>1):
nums.pop(i)
I am getting [0, 1, 2, 3, 3, 4] but am expecting [0, 1, 2, 3, 4].
I see the logic I used worked halfway and removed duplicates until the value 2 but for some reason I don't understand it didn't work for the value 3.
Your logic won't exactly work here. Since you're looping through the number of items in the list and the length of the list is changing, you are at risk at running into an error (IndexError).
Here's another way to approach this problem.
nums = [0,0,1,1,1,2,2,3,3,4]
new_list = []
for i in range(len(nums)):
num = nums[i]
if num not in new_list:
new_list.append(num)
print(new_list)
nums = [0,0,1,1,1,2,2,3,3,4]
seen_n = set()
for i, n in reversed(list(enumerate(nums))):
if n in seen_n:
del nums[i]
else:
seen_n.add(n)
print(nums)
Prints:
[0, 1, 2, 3, 4]
If you are iterating the elements by index number, then you need to remove the elements in reverse order so that the indices of the next elements you visit are not affected by the deletions of previous element. In this code we simply keep track of every unique value we see in a set and test each element of the list against membership in that set to see if it should be deleted.
I just wanted to add that there are many ways to solve this problem. But the question posed was, "Remove duplicates from a list." I take this literally and do not consider creating a second list with duplicates removed to be the same thing as removing duplicates from the original list. You have to ask yourself what if there are other references to the original list? Will they see the change? No.
Your problem is in your misunderstanding of nums.pop(i) : it won't delete all the i items, it would delete just that single item having index i.
So that nums.pop(3) deletes the second 2 item.
# [0,0,1,1,1,2,2,3,3,4]
# [ 0,1,1,1,2,2,3,3,4]
# [ 0, 1,1,2,2,3,3,4]
# [ 0, 1, 2,2,3,3,4]
# [ 0, 1, 2, 3,3,4]
This is a different approach, but it may be worth mentioning that you can also remove duplicates by converting to a dict and back.
nums = [0,0,1,1,1,2,2,3,3,4]
nums = list(dict.fromkeys(nums))
There are already lots of answers to this question, but it seems to me none of them are doing the obvious optimization that comes from the fact that the list is sorted, which means that if a number is a duplicate, it is necessarily identical to its predecessor.
This is how I would solve the question, then, using prev_n != n as the most efficient way to know n has not been seen yet:
nums = [0,0,1,1,1,2,2,3,3,4]
uniq_nums = [nums[0]]
prev_n = nums[0]
for n in nums:
if prev_n != n:
uniq_nums.append(n)
prev_n = n
print(uniq_nums)
try using two lists
nums = [0, 1, 2, 2, 3, 4]
nums2 = []
for i in nums:
if i not in nums2: nums2.append(i)
print(nums2)
edit: previous solution was ineffective, whoops

Deleting items in a list in python

Tried deleting items in a list, no success.
>>> r = [1,2,3,4,5]
>>> for i in r:
if i<3:
del i
>>> print r
[1, 2, 3, 4, 5]
I even tried filtering it,
>>> def f(i):
True if i>2 else False
>>> print list(filter(f,r))
[]
I do not understand why the first one is not working. And I dont understand the result at all, when I use filter(function,iterable).
EDIT:
Seeing Paulo's comment below, now I do not understand why this works.
>>> for i in r:
if i<3:
r.remove(i)
>>> print r
[3, 4, 5]
Shouldn't the iterator problem be still there, and shouldn't the code end up removing only the first element (r[0])
Use a list comprehension instead:
[i for i in r if i >= 3]
and retain instead of delete.
Your filter never returned the test; so you always return None instead and that's false in a boolean context. The following works just fine:
def f(i):
return i > 2
Your initial attempt failed because del i unbinds i, but the list remains unaffected. Only the local name i is cleared.
If you want to delete an item from a list, you need to delete the index:
del r[0]
deletes the first element from the list.
Even if you did manage to delete indices the loop would have held some suprises:
>>> for i, element in enumerate(r):
... if element < 3:
... del r[i]
...
>>> r
[2, 3, 4, 5]
This version fails because the list iterator used by the for loop doesn't know you deleted elements from the list; deleting the value at index 0 shifts up the rest of the list, but the loop iterator looks at item 1 regardless:
first iteration, r = [1, 2, 3, 4, 5], iterator index 0 -> element = 1
second iteration, r = [2, 3, 4, 5], iterator index 1 -> element = 3
I do not understand why the first one is not working.
It is not working because the statement del i undefines the variable i - that is, it deletes it from the scope (global or local) which contains it.
And I dont understand the result at all, when I use filter(function,iterable)
Your function, f does not contain a return statement. Accordingly, it always returns None, which has the boolean equivalent value of False. Thus, filter excludes all values.
What you should probably be doing is filtering using a comprehension, and replacing the list, like so:
r = [i for i in r if i >= 3]
Or, if you really do want to delete part of the original list and modify it, use del on a slice of the list:
del r[:3]
Seeing Paulo's comment below, now I do not understand why [using remove] works.
Because remove(r) searches for the value r in the list, and deletes the first instance of it. Accordingly, repeated modification of the list does not affect the iteration that happens inside remove. However, note that it is still susceptible to the same error, if removal of an item leads to an item being skipped in iteration of the list.

having trouble understanding this code

I just started learning recursion and I have an assignment to write a program that tells the nesting depth of a list. Well, I browsed around and found working code to do this, but I'm still having trouble understanding how it works. Here's the code:
def depth(L) :
nesting = []
for c in L:
if type(c) == type(nesting) :
nesting.append(depth(c))
if len(nesting) > 0:
return 1 + max(nesting)
return 1
So naturally, I start to get confused at the line with the append that calls recursion. Does anyone have a simple way of explaining what's going on here? I'm not sure what is actually being appended, and going through it with test cases in my head isn't helping. Thanks!
edit: sorry if the formatting is poor, I typed this from my phone
Let me show it to you the easy way, change the code like this:
(### are the new lines I added to your code so you can watch what is happening there)
def depth(L) :
nesting = []
for c in L:
if type(c) == type(nesting) :
print 'nesting before append', nesting ###
nesting.append(depth(c))
print 'nesting after append', nesting ###
if len(nesting) > 0:
return 1 + max(nesting)
return 1
Now lets make a list with the depth of three:
l=[[1,2,3],[1,2,[4]],'asdfg']
You can see our list has 3 element. one of them is a list, the other is a list which has another list in itself and the last one is a string. You can clearly see the depth of this list is 3 (i.e there are 2 lists nested together in the second element of the main list)
Lets run this code:
>>> depth(l)
nesting before append []
nesting after append [1]
nesting before append [1]
nesting before append []
nesting after append [1]
nesting after append [1, 2]
3
Piece of cake! this function appends 1 to the nesting. then if the element has also another list it appends 1 + maximum number in nesting which is the number of time function has been called itself. and if the element is a string, it skips it.
At the end, it returns the maximum number in the nesting which is the maximum number of times recursion happened, which is the number of time there is a list inside list in the main list, aka depth. In our case recursion happened twice for the second element + 1=3 as we expected.
If you still have problem getting it, try to add more print statements or other variables to the function and watch them carefully and eventually you'll get it.
So what this seems to be is a function that takes a list and calculates, as you put it, the nesting depth of it. nesting is a list, so what if type(c) == type(nesting) is saying is: if the item in list L is a list, run the function again and append it and when it runs the function again, it will do the same test until there are no more nested lists in list L and then return 1 + the max amount of nested lists because every list has a depth of 1.
Please tell me if any of this is unclear
Let's start with a couple of examples.
First, let's consider a list with only one level of depth. For Example, [1, 2, 3].
In the above list, the code starts with a call to depth() with L = [1, 2, 3]. It makes an empty list nesting. Iterates over all the elements of L i.e 1, 2, 3 and does not find a single element which passes the test type(c) == type(nesting). The check that len(nesting) > 0 fails and the code returns a 1, which is the depth of the list.
Next, let's take an example with a depth of 2, i.e [[1, 2], 3]. The function depth() is called with L = [[1, 2], 3] and an empty list nesting is created. The loop iterates over the 2 elements of L i.e [1, 2] , 3 and since type([1, 2]) == type(nesting), nesting.append(depth(c)) is called. Similar to the previous example, depth(c) i.e depth([1, 2]) returns a 1 and nesting now becomes [1]. After the execution of the loop, the code evaluates the test len(nesting) > 0 which results in True and 1 + max(nesting) which is 1 + 1 = 2 is returned.
Similarly, the code follows for the depth 3 and so on.
Hope this was helpful.
This algorithm visits the nested lists and adds one for each level of recursion. The call chain is like this:
depth([1, 2, [3, [4, 5], 6], 7]) =
1 + depth([3, [4, 5], 6]) = 3
1 + depth([4, 5]) = 2
1
Since depth([4,5]) never enters the if type(c) == type(nesting) condition because no element is a list, it returns 1 from the outer return, which is the base case.
In the case where, for a given depth, you have more than one nested list, e.g. [1, [2, 3], [4, [5, 6]], both the max depth of [2,3]and [4, [5, 6]] are appended on a depth call, of which the max is returned by the inside return.

Categories