Python - iterating over lists - python

I want my code's 2nd function to modify the new list made by my 1st function.
If I am understanding things correctly giving a list as an argument will give the original list (my_list in this case).
so the code removes 1 & 5 and then adds 6, but not 7?
my_list = [1, 2, 3, 4, 5]
def add_item_to_list(ordered_list):
# Appends new item to end of list which is the (last item + 1)
ordered_list.append(my_list[-1] + 1)
def remove_items_from_list(ordered_list, items_to_remove):
# Removes all values, found in items_to_remove list, from my_list
for items_to_remove in ordered_list:
ordered_list.remove(items_to_remove)
if __name__ == '__main__':
print(my_list)
add_item_to_list(my_list)
add_item_to_list(my_list)
add_item_to_list(my_list)
print(my_list)
remove_items_from_list(my_list, [1,5,6])
print(my_list)
output of
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6, 7, 8]
[2, 4, 6, 8]
instead of wanted
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6, 7, 8]
[2, 3, 4, 7, 8]
Thank you and sorry for the elementary question

In your remove_items_from_list function you are iterating through the wrong list. You should iterate through every item in the items_to_remove list like this:
def remove_items_from_list(ordered_list, items_to_remove):
# Removes all values, found in items_to_remove list, from my_list
for item in items_to_remove:
ordered_list.remove(item)
This will now iterate through each item in the remove list and remove it from you ordered_list.

There is a bug in the remove_items_from_list function. For it to achieve what you want it should go:
def remove_items_from_list(ordered_list, items_to_remove):
# Removes all values, found in items_to_remove list, from my_list
for item in items_to_remove:
ordered_list.remove(item)
As a side note, your code has incorrect number of blank lines before function definitions. Should be two blank lines before the function, and not more than one blank line inside functions. It seems not to have affected the code for now, but makes it harder to read, and could cause problems in future.

In the second function you want to iterate over items_to_remove (and not your original list) and then remove every item.

Use:
def remove_items_from_list(ordered_list, items_to_remove):
for item_to_remove in items_to_remove:
ordered_list.remove(item_to_remove)
And don't change the a list when you are iterating over it,which may cause bug.

Related

How to remove some elements from a list and append them at the beginning of the list in Python

Suppose that I have a list that has [0, 1, 2, 3 , 4, 5, 6] in it. I want to remove those elements that are greater than or equal to 3 and add those removed elements to the beginning of the list. So I wrote the code below:
list = [0, 1, 2, 3, 4, 5, 6]
new_list =[]
for number in list:
if number >= 3:
dropped_number = list.pop()
new_list.append(dropped_number)
new_list.sort()
new_list += list
print(new_list)
However, when I ran the code, the result was displayed as [5, 6, 0, 1, 2, 3 , 4]. Could anyone please explain to me at which step I did wrong here?
There are two issues with your code.
the number you obtain with list.pop() is not the one you just checked with your condition (it is merely the last one in the list)
When you reach 3, list.pop() removes 6,
When you reach 4, list.pop() removes 5,
You never reach 5 because you're at the end of what remains of the list at that point.
removing items from a list within a for-loop on the same list will cause the for-loop to skip items or complain that the list changed during iterations. So, even if you were to pop the appropriate number, your loop would miss items.
You also don't need to sort new_list every time you add to it, you can do it once at the end, but that just optimization.
Instead of a for-loop, you could use the sort method with a key parameter that returns a boolean indicating True for elements that do not meet your conditions (i.e that will be shifted to the right). Because Python's sort is stable, this will only place elements in two groups without otherwise changing their relative order.
L = [0, 2, 4, 6, 1, 3, 5]
L.sort(key=lambda x: not x>=3)
print(L) # [4, 6, 3, 5, 0, 2, 1]
If you need a more procedural solution, you can separate the values in two lists that you stick together at the end:
L = [0, 2, 4, 6, 1, 3, 5]
left,right = [], []
for x in L:
if x >= 3: left.append(x)
else: right.append(x)
L = left + right
# [4, 6, 3, 5, 0, 2, 1]
Modifying a list while iterating over it is usually problematic. What if instead you thought of the problem as building a new list out of two subsets of the original list?
>>> old_list = list(range(7))
>>> [i for i in old_list if i >= 3] + [i for i in old_list if i < 3]
[3, 4, 5, 6, 0, 1, 2]
The reason your program doesn't work is because you are modifying the list whilst searching through it. Instead, you can start by adding the elements >= 3 to a new list and then separately appending the elements < 3 to the list. Also, considering you are created a second 'new_list', there is no need to remove the elements from the first list.
Your new code:
list = [0, 1, 2, 3, 4, 5, 6]
new_list = []
# Append numbers greater than 3 to the new list
for number in list:
if number >= 3:
new_list.append(number)
# Append the numbers less than 3 to the new list
new_list += list[0:list.index(new_list[0])]
print(new_list)
Just to note, this method takes a section of the original list from position 0, to the position (.index) of the first item in the new list, which automatically generates the < 3 condition as the first item in the new list corresponds to the items before the >= 3 condition is met.
list[0:list.index(new_list[0])]

I don't understand the difference between these codes [duplicate]

This question already has answers here:
Difference between del, remove, and pop on lists
(14 answers)
Closed 2 years ago.
data = [2, 4, 3, 1, 5, 10, 9]
data.pop()
print(data)
result: [2, 4, 3, 1, 5, 10]
the above is what i think makes sense
however,
data = [2, 4, 3, 1, 5, 10, 9]
Print(data.pop())
I got this
Result : 9
what is the difference?
In the 1st situation, you are printing a list of data. I have re-lined the code and added comments to make it more understandable:
Scenario 1:
data = [2, 4, 3, 1, 5, 10, 9] # the given data list
data.pop() # pop the last element off the list
print(data) # print 'data' (which is the list)
The reason why the result here is [2, 4, 3, 1, 5, 10] is because you are popping from the list, and then printing the list itself.
Scenario 2:
data = [2, 4, 3, 1, 5, 10, 9] # the given data list
print(data.pop()) # print the value returned by data.pop(), which is 9
# Result : 9
List.pop() is a method that returns the popped value from the list. So, by doing print(data.pop()), you are requesting to print the single popped value rather than the data list in its entirety.
See the Python documentation on the List.pop() method here.
The pop() method returns the value which was deleted from the list.
If you try to print that d.pop() it just returns the removed value.
When you use pop( ) it returns the last element of the list and internally it deletes last element from the list.
Note that in the first code you’re printing data ( the list ) and in the second one you’re printing what pop returns

How to reorder a python list backwards starting with the 0th element?

I'm trying to go through a list in reverse order, starting with the -0 indexed item (which is also the 0th item), rather than the -1 indexed item, so that I'll now have the new list to use. I've come up with two ways to do this, but neither seems both concise and clear.
a_list = [1, 2, 3, 4, 5]
print(a_list[:1] + a_list[:0:-1]) # take two slices of the list and add them
# [1, 5, 4, 3, 2]
list_range = range(-len(a_list)+1,1)[::-1] # create an appropriate new index range mapping
print([a_list[i] for i in list_range]) # list comprehension on the new range mapping
# [1, 5, 4, 3, 2]
Is there a way in python 3 to use slicing or another method to achieve this more simply?
If you are up for a programming golf:
>>> a_list = [1, 2, 3, 4, 5]
>>> [a_list[-i] for i in range(len(a_list))]
[1, 5, 4, 3, 2]
I think your first suggestion is the cleanest way of doing this. If you're really optimizing for character count, you can remove two characters from the first slice:
print(a_list[:1] + a_list[:0:-1])
Shift everything left by one and reverse.
my_list.append(my_list.pop(0))
print my_list[::-1]

Is there a way to get the remainder of a list slice without copying the list

With a string in python, I can easily get the remainder of a slice by doing this
my_string = 'pythonisawesome'
print(my_string.replace(my_string[6:8], ''))
print(my_string)
This Outputs
pythonwesome
pythonisawesome
I don't need to copy the string because python strings are immutable so the first result is discarded since a name is not assigned to it and my_string remains unchanged
But this operation is not possible for lists since lists are mutable, for example:
my_list = [1,2,3,4,5,6,7,8,9,10]
del my_list[6:8] # or my_list[6:8] = ''
print(my_list)
Outputs
[1, 2, 3, 4, 5, 6, 9, 10]
Also I also find it a bit strange that my_list is modified while I delete the slice, I believe slices are supposed to cut out a part of the list as a copy and not act the way indexes do
because doing:
my_otherlist = my_list[:]
creates a new copy of the list(when it's not nested) and can be modified without affecting the original list
The main point I'm driving at is that python should have a method that takes slices and returns the remainder of the slice
like list.chopoff[::]
Maybe there's a method but I didn't come across it in the standard library.
If you wanted a new list you would have to do it manually like
my_list = [1,2,3,4,5,6,7,8,9,10]
print(my_list[:6] + my_list[8:])
print(my_list)
It gives Output like
[1, 2, 3, 4, 5, 6, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

How to append multiple values to a list in Python

I am trying to figure out how to append multiple values to a list in Python. I know there are few methods to do so, such as manually input the values, or put the append operation in a for loop, or the append and extend functions.
However, I wonder if there is a more neat way to do so? Maybe a certain package or function?
You can use the sequence method list.extend to extend the list by multiple values from any kind of iterable, being it another list or any other thing that provides a sequence of values.
>>> lst = [1, 2]
>>> lst.append(3)
>>> lst.append(4)
>>> lst
[1, 2, 3, 4]
>>> lst.extend([5, 6, 7])
>>> lst.extend((8, 9, 10))
>>> lst
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> lst.extend(range(11, 14))
>>> lst
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
So you can use list.append() to append a single value, and list.extend() to append multiple values.
Other than the append function, if by "multiple values" you mean another list, you can simply concatenate them like so.
>>> a = [1,2,3]
>>> b = [4,5,6]
>>> a + b
[1, 2, 3, 4, 5, 6]
If you take a look at the official docs, you'll see right below append, extend. That's what your looking for.
There's also itertools.chain if you are more interested in efficient iteration than ending up with a fully populated data structure.
if the number of items was saved in a variable say n. you can use list comprehension and plus sign for list expansion.
lst = ['A', 'B']
n = 1
new_lst = lst + ['flag'+str(x) for x in range(n)]
print(my_lst)
>>> ['A','B','flag0','flag1']
One way you can work around this type of problem is -
Here we are inserting a list to the existing list by creating a variable new_values.
Note that we are inserting the values in the second index, i.e. a[2]
a = [1, 2, 7, 8]
new_values = [3, 4, 5, 6]
a.insert(2, new_values)
print(a)
But here insert() method will append the values as a list.
So here goes another way of doing the same thing, but this time, we'll actually insert the values in between the items.
a = [1, 2, 7, 8]
a[2:2] = [3,4,5,6]
print(a)

Categories