I am trying to write a function to remove duplicates in list using a for loop in python. This is what I've got:
[IN]:
L = [1, 1, "a", "b", 1, "a", "d"]
N = [ ]
def remove_dup(x):
for x in range(len(L)):
if L[x] not in N:
N.append(x)
return N
print(remove_dup(N))
My problem is instead of outputting [1, "a", "b", "d"] its returning this:
[OUT]:
[1, 2, 3, 4, 5, 6]
Lol idk where there is coming from. At least its printing a list though.... Can someone help a girl out and tell me why I am getting a randomly generated list? I have tried switching out a bunch of variables when calling my function.
Thank you!
To N, you are appending x instead of L[x].
You're iterating over the indices rather than the values, and then appending those to your new list. You need to either look up the element to add it, or just iterate over the values directly -- since you don't actually need the index for anything, this is going to be more convenient and readable code.
Separately, it's not a good idea to use a global list like that to return results, since it'll cause problems when you try to use your function more than once. Instead, create the "return" list inside your function. Also, you're not actually using the list passed in to the function (named x) -- you're just looking up values in the global L list instead. Which will also cause problems if you try to use your function with a different list.
So to fix all of those issues, and with variable names edited for readability:
# Iterating over indices
def remove_dups(in_list):
result = []
for index in range(len(in_list)):
if in_list[index] not in result:
result.append(in_list[index])
return result
# Or over values (more readable):
def remove_dups(in_list):
result = []
for item in in_list:
if item not in result:
result.append(item)
return result
Finally - using in on a list isn't the best way to check for duplicates, since it'll search the whole list every time. A much more convenient and performant way of doing this is to just convert it to a set and back:
def remove_dups(in_list):
return list(set(in_list))
With the caveat that this will not keep the list elements in their original order.
Instead of N.append(x) use:
N.append(L[x])
In your case x is an index that goes from 0 to the size of L minus one. But you need the values that can be taken from L by index x.
In addition to the other answers about using L[x] as opposed to just x you could do something like this instead:
L = [1, 1, "a", "b", 1, "a", "d"]
N = [ ]
def remove_dup(x):
for x in L:
if x not in N:
N.append(x)
return N
print(remove_dup(N))
This way is slightly more readable in my opinion, instead of using indexes you're using the values. Either way works.
Related
My goal is to write a program that removes duplicated elements from a list – E.g., [2,3,4,5,4,6,5] →[2,3,4,5,6] without the function set (only if and for)
At the end of my code I got stuck. I have tried to change everything in the if statement but it got me to nowhere, same error repeating itself here:
n=int(input('enter the number of elements in your list '))
mylist=[]
for i in range (n):
for j in range (n):
ele=input(' ')
if mylist[i]!=mylist[j]: ***here is the error exactly , I dont really understand what does the out-of-range above problem have to do with the if statement right here***
mylist.append(ele)
print(mylist)
However, I changed nearly everything and I still got the following error:
if mylist[i]!=mylist[j]:
IndexError: list index out of range
Why does this issue keep coming back? ps: I cant use the function set because I am required to use if and for only
You can do this all with a list comprehension that checks if the value has previously appeared in the list slice that you have already looped over.
mylist = [1,2,3,3,4,5,6,4,1,2,4,3]
outlist = [x for index, x in enumerate(mylist) if x not in mylist[:index]]
print(outlist)
Output
[1, 2, 3, 4, 5, 6]
In case you're not familiar with list comprehensions yet, the above comprehension is functionally equivalent to:
outlist = []
for index, x in enumerate(mylist):
if x not in mylist[:index]:
outlist.append(x)
print(outlist)
A set would be more efficient, but
>>> def dedupe(L):
... seen = []
... return [seen.append(e) or e for e in L if e not in seen]
...
>>> dedupe([2,3,4,5,4,6,5])
[2, 3, 4, 5, 6]
This is not just a toy solution. Because sets can only contain hashable types, you might really have reason to resort to this kind of thing. This approach entails a linear search of the seen items, which is fine for small cases, but is slow compared to hashing.
It still may be possible to do better than this in some cases. Even if you can't hash them, if you can at least sort the seen elements, then you can speed up the search to logarithmic time by using a binary search. (See bisect).
This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 7 years ago.
I have a list
a = ["a", "b", "c", "d", "e"]
I want to remove elements in this list in a for loop like below:
for item in a:
print(item)
a.remove(item)
But it doesn't work. What can I do?
You are not permitted to remove elements from the list while iterating over it using a for loop.
The best way to rewrite the code depends on what it is you're trying to do.
For example, your code is equivalent to:
for item in a:
print(item)
a[:] = []
Alternatively, you could use a while loop:
while a:
print(a.pop())
I'm trying to remove items if they match a condition. Then I go to next item.
You could copy every element that doesn't match the condition into a second list:
result = []
for item in a:
if condition is False:
result.append(item)
a = result
Alternatively, you could use filter or a list comprehension and assign the result back to a:
a = filter(lambda item:... , a)
or
a = [item for item in a if ...]
where ... stands for the condition that you need to check.
Iterate through a copy of the list:
>>> a = ["a", "b", "c", "d", "e"]
>>> for item in a[:]:
print(item)
if item == "b":
a.remove(item)
a
b
c
d
e
>>> print(a)
['a', 'c', 'd', 'e']
As other answers have said, the best way to do this involves making a new list - either iterate over a copy, or construct a list with only the elements you want and assign it back to the same variable. The difference between these depends on your use case, since they affect other variables for the original list differently (or, rather, the first affects them, the second doesn't).
If a copy isn't an option for some reason, you do have one other option that relies on an understanding of why modifying a list you're iterating breaks. List iteration works by keeping track of an index, incrementing it each time around the loop until it falls off the end of the list. So, if you remove at (or before) the current index, everything from that point until the end shifts one spot to the left. But the iterator doesn't know about this, and effectively skips the next element since it is now at the current index rather than the next one. However, removing things that are after the current index doesn't affect things.
This implies that if you iterate the list back to front, if you remove an item at the current index, everything to it's right shifts left - but that doesn't matter, since you've already dealt with all the elements to the right of the current position, and you're moving left - the next element to the left is unaffected by the change, and so the iterator gives you the element you expect.
TL;DR:
>>> a = list(range(5))
>>> for b in reversed(a):
if b == 3:
a.remove(b)
>>> a
[0, 1, 2, 4]
However, making a copy is usually better in terms of making your code easy to read. I only mention this possibility for sake of completeness.
import copy
a = ["a", "b", "c", "d", "e"]
b = copy.copy(a)
for item in a:
print(item)
b.remove(item)
a = copy.copy(b)
Works: to avoid changing the list you are iterating on, you make a copy of a, iterate over it and remove the items from b. Then you copy b (the altered copy) back to a.
How about creating a new list and adding elements you want to that new list. You cannot remove elements while iterating through a list
Probably a bit late to answer this but I just found this thread and I had created my own code for it previously...
list = [1,2,3,4,5]
deleteList = []
processNo = 0
for item in list:
if condition:
print(item)
deleteList.insert(0, processNo)
processNo += 1
if len(deleteList) > 0:
for item in deleteList:
del list[item]
It may be a long way of doing it but seems to work well. I create a second list that only holds numbers that relate to the list item to delete. Note the "insert" inserts the list item number at position 0 and pushes the remainder along so when deleting the items, the list is deleted from the highest number back to the lowest number so the list stays in sequence.
I have tried this, it gives the output it should give([1,3,2]), however the problem is it keeps printing the output for infinite times without stop,, is there any solutions with out changing the idea of the code.
a= [1,2,2,2,1,3,2]
def rem_dup(L):
while len(L):
for i in L:
y= L.count(i)
if y>1:
L.remove(i)
print L
rem_dup(a)
Unless the point of this function is to exercise your python skills, it sounds like you want a set. A set is like a list but does not allow duplicate values. If you want your final data structure to be a list, you could do something like this:
final_list = list(set(original_list))
One way to safely do this is to loop over the list in reverse and remove only from the back:
>>> for i in range(len(a) - 1, -1, -1):
... if a.count(a[i]) > 1:
... del a[i]
...
>>> a
[1, 2, 3]
But this will be polynomial time, since a.count is linear and so is del a[i].
while len(L) will always be true as long as L had something in it to begin with
Modifying L while using it with the for loop can cause items to be skipped, so you have a bug for some inputs.
If you fix that problem, you shouldn't need the while loop.
As long as the items in a are hashable and you don't mind that the remaining items aren't in the same order when you started, you can create an intermediate set and replace the original contents in-place.
a[:] = set(a)
This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 7 years ago.
I have a list
a = ["a", "b", "c", "d", "e"]
I want to remove elements in this list in a for loop like below:
for item in a:
print(item)
a.remove(item)
But it doesn't work. What can I do?
You are not permitted to remove elements from the list while iterating over it using a for loop.
The best way to rewrite the code depends on what it is you're trying to do.
For example, your code is equivalent to:
for item in a:
print(item)
a[:] = []
Alternatively, you could use a while loop:
while a:
print(a.pop())
I'm trying to remove items if they match a condition. Then I go to next item.
You could copy every element that doesn't match the condition into a second list:
result = []
for item in a:
if condition is False:
result.append(item)
a = result
Alternatively, you could use filter or a list comprehension and assign the result back to a:
a = filter(lambda item:... , a)
or
a = [item for item in a if ...]
where ... stands for the condition that you need to check.
Iterate through a copy of the list:
>>> a = ["a", "b", "c", "d", "e"]
>>> for item in a[:]:
print(item)
if item == "b":
a.remove(item)
a
b
c
d
e
>>> print(a)
['a', 'c', 'd', 'e']
As other answers have said, the best way to do this involves making a new list - either iterate over a copy, or construct a list with only the elements you want and assign it back to the same variable. The difference between these depends on your use case, since they affect other variables for the original list differently (or, rather, the first affects them, the second doesn't).
If a copy isn't an option for some reason, you do have one other option that relies on an understanding of why modifying a list you're iterating breaks. List iteration works by keeping track of an index, incrementing it each time around the loop until it falls off the end of the list. So, if you remove at (or before) the current index, everything from that point until the end shifts one spot to the left. But the iterator doesn't know about this, and effectively skips the next element since it is now at the current index rather than the next one. However, removing things that are after the current index doesn't affect things.
This implies that if you iterate the list back to front, if you remove an item at the current index, everything to it's right shifts left - but that doesn't matter, since you've already dealt with all the elements to the right of the current position, and you're moving left - the next element to the left is unaffected by the change, and so the iterator gives you the element you expect.
TL;DR:
>>> a = list(range(5))
>>> for b in reversed(a):
if b == 3:
a.remove(b)
>>> a
[0, 1, 2, 4]
However, making a copy is usually better in terms of making your code easy to read. I only mention this possibility for sake of completeness.
import copy
a = ["a", "b", "c", "d", "e"]
b = copy.copy(a)
for item in a:
print(item)
b.remove(item)
a = copy.copy(b)
Works: to avoid changing the list you are iterating on, you make a copy of a, iterate over it and remove the items from b. Then you copy b (the altered copy) back to a.
How about creating a new list and adding elements you want to that new list. You cannot remove elements while iterating through a list
Probably a bit late to answer this but I just found this thread and I had created my own code for it previously...
list = [1,2,3,4,5]
deleteList = []
processNo = 0
for item in list:
if condition:
print(item)
deleteList.insert(0, processNo)
processNo += 1
if len(deleteList) > 0:
for item in deleteList:
del list[item]
It may be a long way of doing it but seems to work well. I create a second list that only holds numbers that relate to the list item to delete. Note the "insert" inserts the list item number at position 0 and pushes the remainder along so when deleting the items, the list is deleted from the highest number back to the lowest number so the list stays in sequence.
This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 7 years ago.
I have a list
a = ["a", "b", "c", "d", "e"]
I want to remove elements in this list in a for loop like below:
for item in a:
print(item)
a.remove(item)
But it doesn't work. What can I do?
You are not permitted to remove elements from the list while iterating over it using a for loop.
The best way to rewrite the code depends on what it is you're trying to do.
For example, your code is equivalent to:
for item in a:
print(item)
a[:] = []
Alternatively, you could use a while loop:
while a:
print(a.pop())
I'm trying to remove items if they match a condition. Then I go to next item.
You could copy every element that doesn't match the condition into a second list:
result = []
for item in a:
if condition is False:
result.append(item)
a = result
Alternatively, you could use filter or a list comprehension and assign the result back to a:
a = filter(lambda item:... , a)
or
a = [item for item in a if ...]
where ... stands for the condition that you need to check.
Iterate through a copy of the list:
>>> a = ["a", "b", "c", "d", "e"]
>>> for item in a[:]:
print(item)
if item == "b":
a.remove(item)
a
b
c
d
e
>>> print(a)
['a', 'c', 'd', 'e']
As other answers have said, the best way to do this involves making a new list - either iterate over a copy, or construct a list with only the elements you want and assign it back to the same variable. The difference between these depends on your use case, since they affect other variables for the original list differently (or, rather, the first affects them, the second doesn't).
If a copy isn't an option for some reason, you do have one other option that relies on an understanding of why modifying a list you're iterating breaks. List iteration works by keeping track of an index, incrementing it each time around the loop until it falls off the end of the list. So, if you remove at (or before) the current index, everything from that point until the end shifts one spot to the left. But the iterator doesn't know about this, and effectively skips the next element since it is now at the current index rather than the next one. However, removing things that are after the current index doesn't affect things.
This implies that if you iterate the list back to front, if you remove an item at the current index, everything to it's right shifts left - but that doesn't matter, since you've already dealt with all the elements to the right of the current position, and you're moving left - the next element to the left is unaffected by the change, and so the iterator gives you the element you expect.
TL;DR:
>>> a = list(range(5))
>>> for b in reversed(a):
if b == 3:
a.remove(b)
>>> a
[0, 1, 2, 4]
However, making a copy is usually better in terms of making your code easy to read. I only mention this possibility for sake of completeness.
import copy
a = ["a", "b", "c", "d", "e"]
b = copy.copy(a)
for item in a:
print(item)
b.remove(item)
a = copy.copy(b)
Works: to avoid changing the list you are iterating on, you make a copy of a, iterate over it and remove the items from b. Then you copy b (the altered copy) back to a.
How about creating a new list and adding elements you want to that new list. You cannot remove elements while iterating through a list
Probably a bit late to answer this but I just found this thread and I had created my own code for it previously...
list = [1,2,3,4,5]
deleteList = []
processNo = 0
for item in list:
if condition:
print(item)
deleteList.insert(0, processNo)
processNo += 1
if len(deleteList) > 0:
for item in deleteList:
del list[item]
It may be a long way of doing it but seems to work well. I create a second list that only holds numbers that relate to the list item to delete. Note the "insert" inserts the list item number at position 0 and pushes the remainder along so when deleting the items, the list is deleted from the highest number back to the lowest number so the list stays in sequence.