Issue in removing a value from the list - python

I get a list of values from a source. And I also have a dictionary of the standard values. I need to remove any value in the list that is not found in the dictionary.
I wrote this code just to test how it works:
alist = [47, 64, 69, 37, 76, 83, 95, 97]
adict = {'A':47, 'B':69, 'C':76, 'D':97}
list2 = list(adict.values())
for i in alist:
if i not in list2:
alist.remove(i)
print(list2,alist)
The output is:
[47, 69, 76, 97] [47, 69, 76, 95, 97]
What I don't understand here is why the value 95 stayed in the new alist generated?
When I check presence of 95 in the list2, it shows correct results as under:
INPUT:
print(95 in list2)
OUTPUT:
False
If I manually remove 95 from the list using alist.remove(95), it does get removed.
So, can anyone please help me understand where I have gone wrong here.
Thanks.

You are removing items of the container on which you are iterating so it is escaping the items. That's why 95 is never got visited and remains in the list.
Try to run below version of your own code... You will get to know how actually the value of 'i' is changing.
alist = [47, 64, 69, 37, 76, 83, 95, 97]
adict = {'A':47, 'B':69, 'C':76, 'D':97}
list2 = list(adict.values())
print("list2: ", list2)
print("alist: ", alist)
print("\n\n for loop")
for i in alist:
print("in loop: ")
print("alist: ", alist)
print("i: ", i)
print("list2: ", list2)
if i not in list2:
print("removing ", i)
alist.remove(i)
print("\n")
print(list2,alist)

See below how to filter the list.
The general problem with the approach in your code is that you manipulate the list while you iterate over it.
Dont do that - the results are unexpected.
alist = [47, 64, 69, 37, 76, 83, 95, 97]
adict = {'A': 47, 'B': 69, 'C': 76, 'D': 97}
filtered = [x for x in alist if x in set(adict.values())]
print(filtered)
output (Note that 95 is not in the new list)
[47, 69, 76, 97]

You are modifying the iterating object. When you iterate over any iterable object, never ever change the iterating object during the iteration.
For your case, you may simply use & in set
alist = [47, 64, 69, 37, 76, 83, 95]
adict = {'A':47, 'B':69, 'C':76, 'D':97}
set1 = set(alist)
set2 = set(adict.values())
alist = list(set1 & set2)
print(alist)
output: [47, 69, 76], I removed the case 97 intentionally.

Your program is correct logically. Because if only executes when the given condition is True .
Now, your condition is: if i not in list2:
So the program will accept any value other than the items of list2 .
print(95 not in list2)
will give you True output and that's why if statement is executing it.

Related

Trying to swap the first and last elements of a list in Python, but it works only for a predefined list. Not for a list of randomly generated numbers

I was trying to create a python program which swaps the first and last elements of a list. I passed a pre-created list into the algorithm and it worked perfectly. Here's my code:
def swapFirstAndLast(list_to_be_swapped):
size = len(list_to_be_swapped)
list_to_be_swapped[0],list_to_be_swapped[size-1] = list_to_be_swapped[size-1],list_to_be_swapped[0]
return list_to_be_swapped
l = [12,33,42,76,46,97]
swapFirstAndLast(l)
print(l)
Output:
[97, 33, 42, 76, 46, 12]
Then I tried to create functions; one function to create a list of randomly generated numbers, and the second function to perform the swapping operation. Although everything makes sense to me, it is not performing the swapping operation now. This is the code I came up with:
import random
def generateList(size):
list1 = []
for i in range(size):
list1.append(random.randint(0,99))
return list1
def swapFirstAndLast(list_to_be_swapped):
size = len(list_to_be_swapped)
list_to_be_swapped[0],list_to_be_swapped[size-1] = list_to_be_swapped[size-1],list_to_be_swapped[0]
return list_to_be_swapped
l = generateList(5)
l1 = swapFirstAndLast(l)
print(l,l1)
Output:
[49, 78, 63, 82, 72] [49, 78, 63, 82, 72]
As you can see, it does not perform the swapping operation now. I am not able to understand where I am going wrong.
You are swapping the first and the last element of the initial list (i.e., l) too! Please look at this slightly modified example:
import random
def generateList(size):
list1 = []
for i in range(size):
list1.append(random.randint(0,99))
return list1
def swapFirstAndLast(list_to_be_swapped):
size = len(list_to_be_swapped)
list_to_be_swapped[0],list_to_be_swapped[size-1] = list_to_be_swapped[size-1],list_to_be_swapped[0]
return list_to_be_swapped
l = generateList(5)
print(l)
l1 = swapFirstAndLast(l)
print(l, l1)
Output:
[54, 14, 3, 38, 87]
[87, 14, 3, 38, 54] [87, 14, 3, 38, 54]
As you can see, the list l has been changed.
The thing here is that you are not creating a new list, but you're modifying the existing one. It doesn't matter if it has a different name within the function.
If you want to retain the original list l, and also return a separate swapped list l1, you have to create a new list! Here is how you can do it:
import random
def generateList(size):
return [random.randint(0, 99) for _ in range(size)]
def swapFirstAndLast(list_to_be_swapped):
new_list = list_to_be_swapped.copy()
new_list[0], new_list[-1] = new_list[-1], new_list[0]
return new_list
l = generateList(5)
print(l)
l1 = swapFirstAndLast(l)
print(l, l1)
Output:
[38, 59, 86, 26, 19]
[38, 59, 86, 26, 19] [19, 59, 86, 26, 38]
your program works ! your function just modifies the list directly, you can see it better if you do this :
l = generateList(5)
print(l)
l1 = swapFirstAndLast(l)
print(l1)
It turns out that you have already swapped the list (i.e. l) it's just when your print (l,l1) that it looks like you haven't swapped it because it's printing the swapped version of (l). put the print(l) line above ( l1 = swapFirstAndLast(l) ) to see it!
the swapping can be done by using index:
def swapFirstAndLast(lst):
lst[0], lst[-1] = lst[-1], lst[0]
return lst
lst = [12,33,42,76,46,97]
print(swapFirstAndLast(lst))
result is: [97, 33, 42, 76, 46, 12]

A difference output with difference ways for make a list that only exist from the dictionary

first i used a list methods remove() to delete the item that doesn't exist in the dictionary values.
The code is like this:
rollNumber = [47, 64, 69, 37, 76, 83, 95, 97]
sampleDict = {'Jhon':47, 'Emma':69, 'Kelly':76, 'Jason':97}
for num in rollNumber:
if num not in sampleDict.values():
rollNumber.remove(num)
print('After removing unwanted element from list', rollNumber)
output : [47,69,76,95,97]
this is wrong answer
the second one i made a empty list and used append() methods from the item that in dictionary.values
the code is like this:
rollNumber = [47, 64, 69, 37, 76, 83, 95, 97]
sampleDict = {'Jhon':47, 'Emma':69, 'Kelly':76, 'Jason':97}
new = []
for num in rollNumber:
if num in sampleDict.values():
new.append(num)
print('After removing unwanted element from list', new)
output : [47,69,76,97]
this the correct answer
Do you guys know why this happens?
I think that the problem is that you are deleting elements while iterating it. You're better off using a list comprehension:
rollNumber = [47, 64, 69, 37, 76, 83, 95, 97]
sampleDict = {'Jhon':47, 'Emma':69, 'Kelly':76, 'Jason':97}
rollNumber = [num for num in rollNumber if num in sampleDict.values()]
print('After removing unwanted element from list', rollNumber)
Outputs:
After removing unwanted element from list [47, 69, 76, 97]
Instead of mutating the list, try using a comprehension to generate a new list
In [2]: vals = list(sampleDict.values())
In [3]: out = [v for v in rollNumber if v in vals]
In [4]: out
Out[4]: [47, 69, 76, 97]
You try to modify a list while iterating on it, this is a common mistake.
Your 2nd way is the correct one, which can be written this way:
print([num for num in rollNumber if num in sampleDict.values()])
Since you are removing the element, it is not impacting the index of for loop and the for loop is skipping some list element due to the changed position of index once the number is removed.
rollNumber = [47, 64, 69, 37, 76, 83, 95, 97]
sampleDict = {'Jhon': 47, 'Emma': 69, 'Kelly': 76, 'Jason': 97}
for num in rollNumber:
print(num)
if num not in sampleDict.values():
rollNumber.remove(num)
print(rollNumber)
print('After removing unwanted element from list', rollNumber)
Result
47
64
[47, 69, 37, 76, 83, 95, 97]
37
[47, 69, 76, 83, 95, 97]
83
[47, 69, 76, 95, 97]
97
After removing unwanted element from list [47, 69, 76, 95, 97]
As you can see in the result for loop does not get executed for 69, 76 and 95 due to change in their index.

Removing patterns in list

I have a list as following:
list=[80,"error",100,74,72,71,"error",39,38,63,"error",82,"error",62,75,23,77,87,"error",36]
and I want to remove "error" from the list :
llist=len(list)
for i in range(llist):
if list[i]=="error":
del list[i]
llist-=1
print(list)
but the compiler still display,"if list[i]=="error":
IndexError: list index out of range".
Where am I wrong?
Thanks in advance!
First don't use keyword list as variable name. Then conditional list comprehension is an easy way to do it:
my_list = [i for i in my_list if i != "error"]
Your problem here is that you are modifying the list length while trying to iterate over it. Perfect recipe for errors...
Your fix:
llist=len(list_)
for i in range(llist):
try:
if list_[i]=="error":
del list_[i]
llist-=1
except IndexError:
pass
print(list_)
OUTPUT:
[80, 100, 74, 72, 71, 39, 38, 63, 82, 62, 75, 23, 77, 87, 36]
Suggested:
Looks like you only need the numbers from the list:
import numbers
print([x for x in list_ if isinstance(x, numbers.Number)])
OUTPUT:
[80, 100, 74, 72, 71, 39, 38, 63, 82, 62, 75, 23, 77, 87, 36]
OR:
print([num for num in list_ if isinstance(num, (int,float))])
Try using remove function.
l = ['a', 'b', 'error', 'c']
l.remove('error')
Try this :
list1 = [i for i in list1 if i != 'error']
Try :
>>> list1=[80,"error",100,74,72,71,"error",39,38,63,"error",82,"error",62,75,23,77,87,"error",36]
>>> filter(lambda a: a != "error", list1)
[80, 100, 74, 72, 71, 39, 38, 63, 82, 62, 75, 23, 77, 87, 36]
In the last line, you're using "print(list)" but list is not your variable, even list can't be a variable.
You're changing the list after remove a element, dont do it. With the remove element is ready

Dealing with list of lists

I have a list with around 60000 characters.
The package I'm using takes only lists above 999 characters...
So for this example I have to run the function 60000/999 = 61 times.
Here is how a list looks like as an example:
liste=[ 'item1', 'item2', 'item3', 'item4'...]
Here is the issue, this number of characters will not be the same over time it can be less or more, so I have to take the length of the list into account.
Here is the code I'll use:
ids = function(liste)
for id in ids:
print(id)
I guess an idea should be to do a list of lists, the first big one including the 61 lists of 999 characters for each one and then do a loop:
for lists in list:
ids = function(lists)
for id in ids:
print(id)
Does someone have a better idea and/or knows how to create a list of lists depending on the length of the first big list?
It sounds like you want to process a long list in shorter chunks. You don't need to pre-process the list into a list of short lists. Here's a generator to break a list into sublists. Adapt as needed:
# Quick way to create a long list of numbers.
# I used a size that isn't a multiple of the chunk size to show that it doesn't matter.
items = list(range(105))
# Function to return smaller lists of the larger list.
def chunk(items,n):
for i in range(0,len(items),n):
yield items[i:i+n]
# Break the larger list into length 10 lists.
for subitems in chunk(items,10):
print(subitems) # process as you want...
Output:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
[30, 31, 32, 33, 34, 35, 36, 37, 38, 39]
[40, 41, 42, 43, 44, 45, 46, 47, 48, 49]
[50, 51, 52, 53, 54, 55, 56, 57, 58, 59]
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69]
[70, 71, 72, 73, 74, 75, 76, 77, 78, 79]
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89]
[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
[100, 101, 102, 103, 104]
So your code would look something like:
for sublist in chunk(liste,999):
taxids = accession.taxid(sublist)
for tax in taxids:
print(tax)
You seem to be new to Python. While creating lists in python, you don't need to give a length for that list. Why make a list of lists when you can make a list of strings, and still use it as a list of string? So, you DON'T have to the length into account.
I am not very clear about the question you asked, so correct me if I'm wrong. Also, I'm assuming that accession is a user-made function (made by you), to add new elements to the list.
Following is the code for an already defined liste
# I am assuming the list 'liste' is already defined
taxids = []
for i in liste:
taxids.append(list(i))
print(taxids)
Following is the code for when you want take inputs directly
n = input("no. of inputs that are to be given(the no. of elements that you need in the list): ")
for i in range():
elem = input("Enter the string: ")
taxids.append(list(elem))
print(taxids)
Let me know if this help!

for loop based on dynamic list python

Edit:
The desired behaviour of the program is to find the number sequences that have an increasing trend, so I want to generate from ks list a list like this:
desiredList=[[97,122],[98,111],[98,101,103,103,104]]
I have the following, my goal is to run the for loop based on the length of the list, the list length gets changed inside the for loop itself. Python takes into account only the length before the for loop, when the length of the list is changed in the loop it still takes the older value before the loop. Here is the code:
ks=[97,122,111,98,111,98,101,103,103,104,97]
splitLine=2
counter=[]
for i in range(0,len(ks)):
a=ks[i:splitLine]
while len(a)>1:
for j in range(0,len(a)):
m=j
n=j+1
if(a[m]-a[n]<=0):
c=c+1
k=splitLine+c-1
a.append(ks[k]) #When append happens, the for loop still takes the older value of len(a) instead of new value
else:
a.pop(-1)
counter.append(a)
splitLine=splitLine+1
a=[]
break
A quick fix for your looping problem would be to swap out your for loop for a while loop. Change this:
for j in range(0,len(a)):
# <loop contents>
to this:
j = 0
while j < len(a):
# <loop contents>
j += 1
The for loop is grabbing values of j out of a range (a list in Python 2, and a generator object in Python 3). This range is calculated when the for loop is run the first time; it will not update after that, no matter what you do to a.
The while loop gives you more control in this situation, because you can specify the condition under which you want to exit the loop.
Your implementation is probably nesting too many loops for the problem it is trying to solve.
This first implementation contains an error. See below for the fix.
Try something along these lines perhaps:
l = [97,122,111,98,111,98,101,103,103,104,97]
out = []
acc = []
for v in l:
if len(acc)==0 or v >= acc[-1]:
acc.append(v)
else:
if len(acc) > 1:
out.append(acc)
acc = [v]
print(out)
>>>[[97, 122], [98, 111], [98, 101, 103, 103, 104]]
That previous code is slow and can drop the last found fragment. I found that error while running random tests on it to try an optimized version. The following code shows the original code with the correction and the optimized version which can be 30% faster.
def original(l):
out = []
acc = []
added = False
for v in l:
if len(acc)==0 or v >= acc[-1]:
acc.append(v)
else:
added = False
acc = [v]
if acc is not None and len(acc)>1 and not added:
added = True
out.append(acc)
return out
def optimized(l):
out = []
acc = None
tmp = None
deb_v = False
for v in l:
prev = acc[-1] if (acc is not None and len(acc)) else tmp
if prev is not None and v >= prev:
if tmp is not None:
acc = []
acc.append(tmp)
out.append(acc)
tmp = None
acc.append(v)
else:
acc = None
tmp = v
return out
# The original test data
l = [97,122,111,98,111,98,101,103,103,104,97]
assert original(l) == optimized(l) == [[97,122],[98,111],[98,101,103,103,104]]
# A list that triggered last-fragment-dropped error
l = [57, 16, 6, 19, 40, 3, 4, 13, 2, 70, 85, 65, 32, 69, 54, 51, 95, 74, 92, 46, 45, 26, 0, 61, 99, 43, 67, 71, 97, 10, 18, 73, 88, 47, 33, 82, 25, 75, 93, 80, 23, 37, 87, 90, 49, 15, 35, 63, 17, 64, 5, 72, 89, 21, 50, 8, 41, 86, 31, 78, 52, 76, 56, 42, 77, 36, 11, 60, 39, 22, 68, 27, 24, 28, 59, 96, 29, 38, 12, 79, 53, 9, 83, 94, 34, 14, 7, 48, 30, 20, 66, 62, 91, 58, 81, 1, 98, 44, 55, 84]
assert original(l) == optimized(l)
# Random testing
import random
l = list(range(100))
random.shuffle(l)
assert original(l) == optimized(l)
# Timing!
import timeit
print(timeit.timeit("original(l)", globals={"l":l, "original": original}))
# 43.95869998800117
print(timeit.timeit("optimized(l)", globals={"l":l, "optimized": optimized}))
# 34.82134292599949
As Moinuddin says, the root of your problem isn't clear to us. However, the code below shows how you can keep iterating over a list as its length changes:
def iterate_for_static_list_length(l):
for i in range(len(l)):
yield i
l.append(object())
def iterate_for_dynamic_list_length(l):
for i, _ in enumerate(l):
yield i
l.append(object())
if __name__ == '__main__':
l = [object()] * 3
print('Static implementation')
for value in iterate_for_static_list_length(l):
input(value)
print('\nDynamic implementation')
for value in iterate_for_dynamic_list_length(l):
input(value)
Output
Static implementation
0
1
2
Dynamic implementation
0
1
2
3
4
5
6
7
8
This program will keep going forever. In your code I can see that you conditionally append to the list within the loop, so it seems like it should terminate eventually.

Categories