List won't substract specified numbers - python

I am still a newbie in programming and I need some help
I want to substract 9 from numbers bigger then 9 from a list.
ls = [1, 2, 3, 4 ,5, 6, 7, 8, 9]
odd_num = []
for _ in ls[::2]:
odd_num.append(_)
ls.remove(_)
for _ in odd_num:
multip_elem = _ * 2
ls.append(multip_elem)
for _ in ls:
if _ > 9:
substraction = _ - 9
ls.append(substraction)
ls.remove(_)
print(ls)
This is the output
[2, 4, 6, 8, 2, 6, 14, 1, 9]
14 is still in the list but I am pretty sure is bigger then 9 :))

ls = [1, 2, 3, 4 ,5, 6, 7, 8, 9, 10, 11]
ls = [i-9 if i>9 else i for i in ls]
print(ls)
A pythonic way of turning one list into other.
It uses a mechanism called list comprehension.
I have skipped the part for odd numbers, to simplify it.
This approach first creates a new list, and then assigns it to the same variable.
Note it is generally not a good idea to modify a list while iterating it (adding and removing items).

You should not modify a list while iterating on it, this always causes problems ;)
You'd better iterate over it using it's indices, and replace the value directly
for i in range(len(ls)):
if ls[i] > 9:
ls[i] -= 9
Or use a list comprehension to create a new list from ls:
ls = [i-9 if i>9 else i for i in ls]

There are better answers above (#Mirronelli for instance), but I tried to keep this answer as close as possible to your original code, in case you needed to keep a similar structure.
ls = [1, 2, 3, 4 ,5, 6, 7, 8, 9]
odd_num = []
for element in ls:
# Separate list into odd and even numbers
if element % 2 != 0:
# Create your odd list
odd_num.append(element)
ls.remove(element)
# You don't need to do append here
# Just use a list comprehension
odd_num = [element * 2 for element in odd_num]
# Again, you don't need append/remove here
# Just use a list comprehension
ls = [element for element in ls if element < 9]
print(ls)

Related

I can't figure out how to loop twice in a Function to modify a list

lst = [1,2,3,4,5,6,7,8,9,10]
lst2 =[11,12,13,14,15,16,17,18,19,20]
def even(fn,sn):
for i in sn:
if i %2 == 0:
fn.append(i) # from this point i get this output for lst: [1,2,3,4,5,6,7,8,9,10,12,14,16,18,20]
even(lst,lst2)
print(lst)
What I am trying to do here is take lst2 even numbers add them to lst, then modifying lst into all even numbers. Keep in mind I am trying to do all this in ONE function. if anyone can help me with this, it would be greatly appreciated.
my desire output for lst is [2,4,6,8,10,12,14,16,18,20]
You can use a slice assignment to replace a list with a modified list.
def even(fn, sn):
fn.extend(sn)
fn[:] = [x for x in fn if x % 2 == 0]
Here's one way to do this. Traverse over lst in reverse order, so that we can also remove from the list while iterating over it.
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
lst2 = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
def even(fn, sn):
# Add all elements of second list to the first list
fn.extend(sn)
for i in range(len(fn) -1, -1, -1):
if fn[i] % 2 != 0:
fn.pop(i)
even(lst, lst2)
print(lst)
Here are my sugestion:
def even(fn,sn):
union = fn + sn
return [i for i in union if i % 2 == 0]
With the sum operation you can append all the list "sn" in the final of the list "fn". Then you can consctruct a list with only the even numbers.
I used a list comprehension that make a for loop in one line.

How do I prevent python skipping an integer during an iteration after removing an integer from the list? [duplicate]

This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 2 years ago.
I am attempting to remove duplicates from a list of numbers; however, the code doesn't remove all the duplicates. After debugging, I realized that an integer is skipped if the previous iteration results in the removal of that integer (neither of the 2's in the list are removed as they are preceded by 5 which was a duplicate):
numbers_list = [5, 2, 546, 7, 3, 5, 2, 7, 29, 6, 5, 7]
for item in numbers_list:
if numbers_list.count(item) > 1:
numbers_list.remove(item)
else:
pass
print(numbers_list)
EDIT: I know there are other ways to remove duplicates from a list but I want to know how to ensure that iterations aren't skipped.
Just don't modify a list during iteration -- strange things happen, as you observed. Changing the list affects the iterator, and the results of that are, I think, implementation-defined. Doing it this way is considered bad style, exactly because of those weird effects. The easiest solution for your concrete problem of removing duplicates, which is equivalent to ensuring uniqueness, is to use a set:
unique_list = list(set(numbers_list))
You can leave out the list part if you are only interested in the result as an iterable. However, this (likely) won't preserve the orginal order in numbers_list -- if you need the order, some different approach is needed, like this:
def makeunique(l):
i = 0
while i < len(l):
j = i + 1
while j < len(l):
if l[j] == l[i]:
del l[j]
j += 1
i += 1
return l
(This has quadratic complexity, though.)
if you need to remove duplicates you can use this
numbers_list = [5, 2, 546, 7, 3, 5, 2, 7, 29, 6, 5, 7]
list_no_dubl = list(set(numbers_list))
print(list_no_dubl)
If you want to remove duplicates you can do:
mylist = list(dict.fromkeys(mylist))
If you don't want to skip iterations you can use a while, for example:
counter = 0
while counter < len(mylist):
# if you want to remove an item, don't increase counter, otherwise yes
counter++
The function set() constructs a set object, which ensures that there are only unique, unordered collection of objects.
The function list() converts the set object back into a list.
numbers_list = [5, 2, 546, 7, 3, 5, 2, 7, 29, 6, 5, 7]
deduped_list = list(set(numbers_list))
print(deduped_list)
>>[2, 3, 546, 5, 6, 7, 29]

Why wasn't the last number in that list removed?

This is my Python program:
def highest_even(li):
for num in li:
if num % 2 != 0:
li.remove(num)
return li
print(highest_even([10,2,3,4,5,80,15,99]))
And the output is :
[10, 2, 4, 80, 99]
I want to know why 99 wasn't deleted.
Thanks.
It's generally a bad idea to modify a list that you're iterating over, all sorts of strange things can happen. The particular strange thing that's happening here has to do with the way Python iterates over lists.
Think of Python maintaining the position of the current item for iterating. When you delete an item, the others all shift "left" in the list but Python still advances the position. That means, if you have two odd numbers in a row (like 15 and 99)(a), deleting the 15 moves 99 to the left (to where the 15 was) but the next iteration will be looking at where the 99 was before shifting, not where it is now.
For example, consider the list [1, 3, 6, 8], these are the steps Python will take:
List Pos newList newPos comment
---- --- ------- ------ -------
[1, 3, 6, 8] 0 [3, 6, 8] 1 Odd 1, delete, advance.
[3, 6, 8] 1 [3, 6, 8] 2 Even 6, leave, advance.
[3, 6, 8] 2 [3, 6, 8] 3 Even 8, leave, advance.
[3, 6, 8] 3 iteration finished.
You can see that consecutive odd numbers cause a problem here, it will only delete alternate ones.
As to the solution: if, as your code suggests, you just want the even numbers in the list, you can use the much more succinct (and Pythonic) list comprehension (no need even for a function to do this):
myList = [10, 2, 3, 4, 5, 80, 15, 99]
evens = [item for item in myList if item % 2 == 0]
# gives [10, 2, 4, 80]
And, for completeness, since your function name seems to indicate you want the highest even number, that would be something like:
biggestEven = max([item for item in myList if item % 2 == 0])
# gives 80
(a) Your problem actually has nothing to do with the fact the 99 is at the end of the list, any consecutive odd numbers, anywhere in the list, would cause the same issue.
do not modify a list you iterate in
you can copy before iterate on
def highest_even(li):
for num in li.copy():
if num % 2 != 0:
li.remove(num)
return li
print(highest_even([10,2,3,4,5,80,15,99]))
Execution :
[10, 2, 4, 80]
As so many comments mention: it's unsafe (or at least it presents some unexpected behavior) to modify a list as you iterate over it. The usual fix here for lists that aren't giant is simply to copy the list when you go to iterate on it.
for num in li[:]:
# everything as before
That little slice syntax makes Python take the list li, create a new list of its entire contents, and iterate over that, instead. Now since you're removing things from li, but iterating over the copy of li made by slicing it, there's no issue.
this is because of you iterated through the list while editing it.
only_even = []
for n in lst:
if not n % 2:
only_even.append(n)
other methods
only_even = [n for n in lst if not n % 2]
only_even = list(filter(lambda x: not n % 2, lst))
You should never update the data structure you are iterating in, to maintain the invariants of the loops.
If you print the li, and num right after the for num in li:, you'll see that after you remove the element from the list, the next element is skipped, meaning that the indexed is moved forward, same thing happens to 99 element.
You can check it here.
def highest_even(li):
for num in li:
print(li, num)
if num % 2 != 0:
li.remove(num)
return li
gives the output:
In [3]: highest_even([10,2,3,4,5,80,15,99])
([10, 2, 3, 4, 5, 80, 15, 99], 10)
([10, 2, 3, 4, 5, 80, 15, 99], 2)
([10, 2, 3, 4, 5, 80, 15, 99], 3)
([10, 2, 4, 5, 80, 15, 99], 5)
([10, 2, 4, 80, 15, 99], 15)
Out[3]: [10, 2, 4, 80, 99]
You should not iterate through a list and delete the elements of the same list.
Since the index is used iterate in a loop.
0- 10
1- 2
2- 3
3- 4
4- 5
5- 80
6- 15
7- 99
And as when you delete the elements from list it skips the next element.
In your example, for the indexes 0 & 1 nothing changes. But when index =3 and as per the condition this element is removed and the list would be updated to [10,2,4,5,80,15,99].
After index =3 the next index is 4 and li[4] equals 5 and not 4. And your condition is not even checked for the element 4. It just happened to be even to be correct. Having some odd instead of 4 would again give you wrong output.
Same is the case with the last element 99. Since the previous element 15 or index = 6 is removed the length of the list reduced by 1 and it does not loop for index = 4 as index reached its max value of updated list is 5(after removing 3,5 & 15).
You shouldn't update a list while iterating over it. But you can make it work by going backwards or you will be cutting a tree branch while sitting on it.
li = [10,2,3,4,5,80,15,99]
for i in range(len(li) - 1, -1, -1):
if (i%2 != 0 ):
del li[i]
print(li)
What's happening there is that you are changing a list while you iterate over it, but the iterator on that list will not get updated with your changes.
you can try this:
for i in range len(li):

list only stops once the element of the list is the number 7

I want to write a code that contains a sublist , that only stops once the element of the list is a certain number , for example 9.
I´ve already tried using different operators , if statements .
def sublist (list):
return [x for x in list if x <9]
[7,8,3,2,4,9,51]
the output for the list above should be :
[7,8,3,2,4]
List comprehensions really are for making mapping/filtering combinations. If the length depends on some previous state in the iteration, you're better off with a for-loop, it will be more readable. However, this is a use-case for itertools.takewhile. Here is a functional approach to this task, just for fun, some may even consider it readable:
>>> from itertools import takewhile
>>> from functools import partial
>>> import operator as op
>>> list(takewhile(partial(op.ne, 9), [7,8,3,2,4,9,51]))
[7, 8, 3, 2, 4]
You can use iter() builtin with sentinel value (official doc)
l = [7,8,3,2,4,9,51]
sublist = [*iter(lambda i=iter(l): next(i), 9)]
print(sublist)
Prints:
[7, 8, 3, 2, 4]
To begin with, it's not a good idea to use python keywords like list as variable.
The list comprehension [x for x in list if x < 9] filters out elements less than 9, but it won't stop when it encounters a 9, instead it will go over the entire list
Example:
li = [7,8,3,2,4,9,51,8,7]
print([x for x in li if x < 9])
The output is
[7, 8, 3, 2, 4, 8, 7]
To achieve what you are looking for, you want a for loop which breaks when it encounters a given element (9 in your case)
li = [7,8,3,2,4,9,51]
res = []
item = 9
#Iterate over the list
for x in li:
#If item is encountered, break the loop
if x == item:
break
#Append item to list
res.append(x)
print(res)
The output is
[7, 8, 3, 2, 4]

Confusing behavior of Python for statement

I have the following python code:
x = range(0,10)
print x
for number in x:
print(number)
if number%2<> 0:
x.remove(number)
print x
Oddly, the out put is this:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
0
1
3
5
7
9
[0, 2, 4, 6, 8]
The first and last lines are right, but why are 2,4,6, and 8 not printed out? The print statement is not inside the if statement!
I'm using python(x,y) on windows 7. Also, I'm new to Python...I'm used to C++
You're removing items from the list (x.remove) while iterating over it (for number in x).
for-in maintains an index separately, and that is why modifying the list gives unexpected behavior.
The list is iterated using its index, but when you remove elements you skip some indices.
E.g:
[0,1,2,...] # (iterator is at second - print 1)
remove
[0,2,3,...] # (iterator is still at second)
iterator advances
[0,2,3,...] # (iterator is at third - print 3)
Add some print statements for clarity:
x = range(10)
for index, number in enumerate(x):
print "x is ", x
print "element is", number
print "index is ", index
print
if number % 2 == 0:
x.remove(number)
And the output:
x is [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
element is 0
index is 0
x is [1, 2, 3, 4, 5, 6, 7, 8, 9]
element is 2
index is 1
x is [1, 3, 4, 5, 6, 7, 8, 9]
element is 4
index is 2
x is [1, 3, 5, 6, 7, 8, 9]
element is 6
index is 3
x is [1, 3, 5, 7, 8, 9]
element is 8
index is 4
As you can see, index keeps going up by 1, even though you remove elements from the list. This is what causes the loop to skip elements.
As others have pointed out, looping over a list and removing elements from it isn't a good idea. Loop over a copy instead:
for number in x[:]:
Or:
for number in list(x):
Better yet, make a new list with a list comprehension:
[number for number in x if number % 2 == 0]
Basically you can have weird behavior when you iterate something while removing at the same time. What's happening is that you're skipping some values due to them being shifted to indexes that you already iterated over.
A better way of doing what you want (filter out some items), would be to use a list comprehension, for instance:
[x for x in range(10) if x%2==0]
You could simply use the range step to only create even numbers, but the above solution let's you filter out on any condition.
The reason why some numbers aren't printed is that the values are changing positions while you loop and remove them. When you remove the 1, you can imagine all the values being shifted by one position, the iterator is pointing to where the 2 used to be, but now the value there is 3, so the 2 is never printed. And this goes on for the rest of the values.
As Mark Rushakoff mentions, you shouldn't modify something while you're iterating over it. Change your for number in x to for number in x[:] and it will work as you expect, though. In this case you're iterating over a copy.
Don't modify a list you're iterating over. Others suggest copying the list or collecting a new list of things to remove. Instead, collect the ones you want to remain. This is faster than copying the list and removing from the copy not being iterated over, and faster than collecting the ones to remove and then removing them.
evens = []
for number in x:
if number%2 == 0:
evens += [number]
print(evens)

Categories

Resources