removing elements in list(Python) - python

I have tried execute this, but it dosn't work properly. My goal was to remove all numbers divided by 2. Could someone advise what is wrong. I really do not understand why '4', '8' are still there.
list = [2,4,9,0,4,6,8,3,43,44]
for e in list:
if e%2==0:
list.remove(e)
print(list)

You can use a list comprehension to generate a new list with only elements you want to keep.
newList = [x for x in oldList if not isEven(x)]
where the function isEven does something like:
def isEven(target):
return target % 2 == 0
By the way, your question is a duplicate of the following How to remove items from a list while iterating?

If you want to keep the list instead of creating a new one (the answer by Thomas Milox is a good one otherwise), you should iterate backward through the list by index. When you remove an element from a list while iterating forwards through the list you may jump over some elements, not processing them. Going backward ensures that no list element removals move any elements that you may still want to process.
Here is an example of how this may look for your code:
list = [2, 4, 9, 0, 4, 6, 8, 3, 43, 44]
for i in range(len(list) - 1, -1, -1): # start at the last element, go until the first one (index 0 - the last value in the range method will not be reached), go backwards
if list[i] % 2 == 0:
del list[i]
You can read a bit more about removing an element by index instead of by value here.
This is required since you would otherwise mutate the list on the wrong position for duplicate values. It may also be a bit faster, since removeneeds to iterate through the list, searching for the element to remove while del list[i] may look up the element that needs to be removed by index.
Iterating backward through a list is also covered here.

You can try to use list.pop() with the position of the element you want to remove.
The '2' and '4' are still there because they are skipped when you remove the number before them (When you remove the '2', the '4' is moved to the previous position)

Try this:
l = [2, 3, 4, 5, 9, 10,30,45]
new=[el for el in l if el % 2]
print(new)
Actually, when you remove an element from the list, the indexing gets changed. So, you can do this list comprehension.
Also you can use:
l = [2, 3, 4, 5, 9, 10,30,45]
new=[filter(lambda x: x % 2, l)]
print(new)

Related

How to move items with even index to the end of the list

lst = ['apple', 'orange', 'kiwi', 'ananas',
'tea', 'coffee', 'milk', 'love', 'peace']
for i in range(len(lst)):
if (i + 1) % 2 == 0:
lst.append(lst[i])
lst.pop(i)
Basically here I want the items with even index to be added at the end of this list
it works for the second item but still doesn’t for the rest of them
You can use Python's wider-step ranges:
lst = lst[1::2] + lst[0::2]
The right hand side of the plus says "grab every 2nd element starting from the first" and the left hand side says "grab every 2nd element starting from the second". This basically reconstructs the list with the odd elements first and the even elements last.
It even avoids expensive pops that make your reference algorithm O(n^2)
The problem with your approach is that the elements shift after you moved the first element. So when you are at the next element with "even" index, the element that's there was originally at an odd index. Thus, after you shift the first element, you can just directly continue with the element at the next index, which previously was two indices away, then again the next one, and so on, for half the indices in the list.
Here's an example, using a list of numbers so it's easier to see what happens. If you want odd indices instead, use range(1, len(lst)//2+1).
lst = list(range(10))
for i in range(len(lst)//2):
lst.append(lst.pop(i))
# [1, 3, 5, 7, 9, 0, 2, 4, 6, 8]
However, even if this works, modifying a list while iterating it is generally a very bad idea leading to many headaches. Also, that repeated pop(i) makes the whole operation O(n²).
Instead, it would be much faster and saner to just combine two slices of the list:
lst = list(range(10))
lst = lst[1::2] + lst[0::2]
# [1, 3, 5, 7, 9, 0, 2, 4, 6, 8]
(If you need to change the list "in-place", e.g. because of other references pointing to that list, you can replace the content of the list using an assignment to a slice: lst[:] = .... This would still not be "in-place" in the sense of not using additional memory. But if the list is so big that this is a problem, then the O(n²) running time will probably be a bigger problem anyway.)
A simple way would be to build a new list by using comprehensions:
lst2 = [v for i, v in enumerate(lst) if i%2 == 0] + \
[v for i, v in enumerate(lst) if i%2 != 0]
But it is possible to change the list in place. The rule is to start from the end of the list in order not to change oddness of indices when an element is removed
last = len(lst) - 1 # when an element is popped, the list loses one element
for i in range(len(lst), 0, -1):
if (i % 2) == 0:
val = lst.pop(i - 1) # remove element with even index
lst.insert(last, val) # insert it before last inserted
last -= 1

The second to the last line of code is confusing to me

I am quite new to python and programming in general so I am still trying to understand the details in practice. This is a problem I found online so I can practice nested loops more. If my question is missing anything or you do not understand my question, please let me know. I would like to get better at asking good questions as well.
list =[[1, 2], [3,4]]
m = 1
print(list)
for i in range(0, 2):
m *= 10
for j in range(0, 2):
list[i][j] *= m # This part right here.
print(list)
This is what prints on the terminal:
[[1, 2], [3, 4]]
[[10, 20], [300, 400]]
I was trying to go through this block of code step by step to make sure I understand it but this part is stumping me. I understand that the whole function of this nested for loop is to multiply the items in the 1st list with 10 and the 2nd list with 100. I also know what the *= m part is, the part that's confusing to me is the code right before that on the same line.
So far I tried to just copy this specific part in google and see if anything came up. I could not find anything that would make sense. I also tried to just run this whole line and see what printed (list[i][j] *= m)(I changed the variable to numbers obviously). That only came up with a type error... There are no type variables left in list[2]. I was trying to isolate it to see what just this part does but it apparently doesn't work like that. I guess i need to think outside the box a little more maybe.
If we take i to be 1 and j to be 1, list[i][j] would be 4. list[i] = [3,4] so what you're doing is finding index 1 of the list [3, 4]
list is a list containing nested lists.
list[0] is the list [1, 2]. list[1] is the list [3, 4].
When you use two indexes like list[i][j], it first gets the nested list list[i], then accesses the [j] element of that. So when i == 0 and j == 1, this accesses the list element containing 2.
*= m then multiplies that list element. So when i == 0 and m == 10, it multiplies the values in the first sublist by 10. Then when i == 1 and m == 100 it multiplies the values in the second sublist by 100.
list = [[1,2], [3,4]] is an array of arrays.
To get a single element, you have to subscript list twice, which is exactly what list[i][j] is.
list[0] returns [1,2], the 0-th element of the list, which is a sublist
list[0][0] returns 1, the 0-th element of the 0-th sublist
list[0][1] returns 2, the 1st element of the 0-th sublist
.
list[1] returns [3,4], the 1st element of the list, which is a sublist
list[1][0] returns 3, the 0-th element of the 1st sublist
list[1][1] returns 4, the 1st element of the 1st sublist
.
Also, the reason why list[2] doesn't return anything is because list only has two elements, which have the index 0 and 1, so trying to get the element at index 2 will not work

Python. Greedy algorithm, 2 for loops iterating over lists

I am trying to write a greedy algorithm where I have a constraint on how many items I can fit into a box and I have to fit as many items in a box as possible before moving on to the next one (ie maximizing the weight of each box).
I've been trying to solve this by creating two identical lists, let's say a_list and b_list.
a_list = [9, 8, 6, 4, 3, 2, 2, 2]
b_list = [9, 8, 6, 4, 3, 2, 2, 2]
The constraint on each box is 10 here, so for example I can only fit the first item (9) into one before moving onto the next box. The following box should contain 8 + 2.
Each box is a list within the main list ie
list_ = [[9], [8,2],[6,4].....]
I can only move on to next box once the current one cannot have further items fitted into it.
When I am trying iterate through the two lists I don't know how to delete items to avoid them appearing multiple times in list_.
I'm close but I have a couple of items coming up twice while one doesn't come up at all.
It is also the case that despite my sorting the lists in descending order, not all my boxes are optimal, one of them only has one item with value '2' in it. I know it's to do with the loop but I don't understand why it's not going through the items in descending order.
limit = 10
list_ = [[]]
for i in a_list:
for j in b_list:
if sum(l[-1]) + i + j <= limit:
l[-1].append(i)
l[-1].append(j)
b_list.remove(j)
elif sum(l[-1]) + j <= limit:
l[-1].append(j)
b_list.remove(j)
else:
l.append([])
The only reason I think that you're using an a_list and a b_list is that you assume you need to pick two items per box, which need not be the case.
I think you should use a single list, and use a list index based approach to track which items are added.
You also will have issues with deletes, so try setting items that are added to -1 and filter them out after each pass, to avoid confusions with deletes while looping.
I'm resisting sharing the solution code here, but ping me if you need it.
Changing a list as you iterate over it is always a challenge. Here is one solution that uses a while loop, which I generally don't endorse, but it is a simple enough algorithms that it should work here with no issues.
The while loop checks if there are any elements left in the initial list. It then pops (removes and saves) the first element of the list and iterates over the rest of the list looking for additional elements that satisfy the condition of the summing to less than the constraint. If an element is found it is appended to sub-list and its index is recorded. At the end of the for loop the sub list is append to the output list and then recorded indices are removed in the reverse order.
a_list = [9, 8, 6, 4, 3, 2, 2, 2]
constraint = 10
out = []
while a_list:
# grab first element of a_list and reset the list of
# to pop from a_list to pop from a_list
sub_out = [a_list.pop(0)]
pop_list = []
for i,a in enumerate(a_list):
if a+sum(sub_out) <= constraint:
sub_out.append(a)
pop_list.append(i)
# append the sub_list to the output list
out.append(sub_out)
# remove each item in the pop_list in the reverse order
for i in reversed(pop_list):
a_list.pop(i)
#output:
>>> out
[[9], [8, 2], [6, 4], [3, 2, 2]]

Using for loop in Python 3.4 to remove particular element from array

As I am new to programming in Python. I am trying to remove particular elements from array using for loop which looks like
a=[2,3,1,4,1,1,1,5]
n=a.count(1)
for i in range (len(a)-n):
if (a[i]==1):
del a[i]
else:
a[i]=a[i]
print (a)
I want to remove 1 from array a. But, I am getting result as:
[2, 3, 4, 1, 1, 5].
That is 1 still exists in my new array. Can somebody please answer my problem?
try like this:
a = [2,3,1,4,1,1,1,5]
a = [x for x in a if x!=1] # this is called list comprehension
note Never modify list while iterating
Use a while loop and the remove method:
a = [2, 3, 1, 4, 1, 1, 1, 5]
while 1 in a:
a.remove(1)
print a
The real answer to your question (which none of the other answers addresses) is that every time you remove an item, the index i moves past it.
in your case:
a = [2,3,1,4,1,1,1,5]
after deleting the 5th item in the original list, the pointer moves to the 6th item, and the new 5th item (the second 1 in the sequence of three 1s) is skipped.
Regarding the comment never modify a list in a loop, try to implement an in-place algorithm like Fisher-Yates without modifying the list. Never say never. Know what you're doing.
The OP changes the list in-place, not creating a new list.
There are two methods, the second is safe, the first might be faster.
a = [2, 3, 1, 4, 1, 1, 1, 5]
toremove = 1
for i in range(len(a)-1, -1, -1):
if a[i] == toremove:
del a[i]
and
a = [2, 3, 1, 4, 1, 1, 1, 5]
toremove = 1
for i in range(a.count(toremove)):
a.remove(toremove)
The second removes the element however many times it exists (before the loop). Since we are not iterating on the list, it is safe to use the remove method.
Both fragments should be O(n) (but haven't done the calculations).
You can copy a and then remove but you cannot iterate over and delete elements from the same list, if your list starts with n elements python will have n pointers to each element so removing elements from the list as your are iterating over it will cause elements to be missed.python has no way of knowing you have removed elements from the list:
a = [2,3,1,4,1,1,1,5]
for ele in a[:]:
if ele == 1:
a.remove(1)
print(a)
[2, 3, 4, 5]
You can also use reversed which returns and iterator avoiding creating a whole copy of the list at once:
a = [2,3,1,4,1,1,1,5]
for ele in reversed(a):
if ele == 1:
a.remove(1)
print(a)
[2, 3, 4, 5]
Or using a list comprehension with the [:] syntax so we actually update the original object:
a[:] = (ele for ele in a if ele != 1)
All the above are linear operations using a single pass over a.
Actually as the del statement will remove elements from your list , and as the list that you bound in your loop doesn't been update after the first deleting you remove incorrect elements from your list , so if you want to use del you need to make the list name in your loop to reference to new list , that you can use a function for this aim , but as a more python way you can just use a list comprehension:
>>> a=[2,3,1,4,1,1,1,5]
>>> a=[i for i in a if i !=1]
>>> a
[2, 3, 4, 5]
Or you can use filter :
>>> a=[2,3,1,4,1,1,1,5]
>>> a=filter(lambda x: x !=1,a)
>>> a
[2, 3, 4, 5]

function that given a list returns a list of list decreasing

I'd make a function in python, that given a list returns a list of list, in which every element is the list given decreased by one.
Input: list_decreaser([0,3,4,5,6,7,8)
Output: [[0,3,4,5,6,7],[0,3,4,5,6],[0,3,4,5],[0,3,4],[0,3],[0]]
My attempt:
def list_decreaser(list):
listresult = []
for x in range(len(list)-1):
list.remove(list[x])
listresult.append(list)
return listresult
The code appends the same list multiple times. It should append copy of the list.
And use del list[..] instead of list.remove(list[..]) to delete an item at specific index.
def list_decreaser(xs):
listresult = []
for i in range(len(xs)-1, 0, -1): # <--- interate backward
del xs[i]
listresult.append(xs[:]) # <----
return listresult
print(list_decreaser([0,3,4,5,6,7,8]))
Or using list comprehension:
>>> xs = [0,3,4,5,6,7,8]
>>> [xs[:i] for i in range(len(xs)-1, 0, -1)]
[[0, 3, 4, 5, 6, 7], [0, 3, 4, 5, 6], [0, 3, 4, 5], [0, 3, 4], [0, 3], [0]]
BTW, don't use list as a variable name. It shadows builtin list function.
The problem is that you're appending the same list over and over again. You keep mutating the list in-place, but you're never creating a new list. So you end up with a list of N references to the same empty list.
This is the same problem discussed in two FAQ questions. I think How do I create a multidimensional list explains it best.
Anyway, what you need to do is append a new list each time through the loop. There are two ways to do that.
First, you can append a copy of the current list, instead of the list itself:
def list_decreaser(list):
listresult = []
for x in range(len(list)-1):
list.remove(list[x])
listresult.append(list[:]) # this is the only change
return listresult
This solves your problem, but it leaves a few new problems:
First, list.remove(list[x]) is a very bad idea. If you give it, say, [0, 1, 2, 0], what happens when you try to remove that second 0? You're calling list.remove(0), and there's no way the list can know you wanted the second 0 rather than the first! The right thing to do is call del list[x] or list.pop(x).
But once you fix that, you're removing the elements from the wrong side. x is 0, then 1, then 2, and so on. You remove element 0, then element 1 (which is the original element 2), then element 2 (which is the original element 4), and eventually get an IndexError. Even if you fixed the "skipping an index" issue (which is also explained in the FAQ somewhere), you'd still be removing the first elements rather than the last ones. You can fix that by turning the range around. However, there's an even easier way: Just remove the last element each time, instead of trying to figure out which x is the right thing, which you can do by specifying -1, or just calling pop with no argument. And then you can use a much simpler loop, too:
def list_decreaser(list):
listresult = []
while list:
list.pop()
listresult.append(list[:])
return listresult
Of course this appends the last, empty list, which you apparently didn't want. You can fix that by doing while len(list) >= 1, or putting an if list: listresult.append(list[:]), or in various other ways.
Alternatively, you can make new truncated lists instead of truncating and copying the same list over and over:
def list_decreaser(list):
listresult = []
while len(list):
list = list[:-1]
listresult.append(list)
return listresult
Note that in this second version, rather than changing the value stored in list, we're creating a new list and storing that new list in list.
use this
def list_decreaser(list1):
listresult = []
for i in list1:
list1 = list[:-1]
listresult.append(list1)
return listresult

Categories