I was practicing python 'list variable' with 'for loop', but was surprised to see that the order of the items in the list changed.
xlist=[1,2,3,4,5]
print(xlist)
#loop all items in the lxist
for item in xlist:
print(item)
#multiply each item by 5
xlist[xlist.index(item)] = item * 5
#print the list
print(xlist)
I was expecting the list order to be [5,10,15,20,25] but instead i got [25, 10, 15, 20, 5]
I am using python 3.8(32 version) using pycharm IDE.
Can anyone clarify why the order of the list has changed
You are not using the .index method correctly. Two problems, semantically, it doesn't mean what you think it means, it gives you the first index of some object in a list. So note, on your last iteration:
xlist.index(5) == 0
Because on your first iteration, you set:
xlist[0] = 1 * 5
The correct way to do this is to maintain and index as you iterate, either manually by using something like index = 0 outside the loop and incrementing it, or by iterating over a range and extracting the item using that index. But the pythonic way to do this is to use enumerate, which automatically provides a counter when you loop:
for index, item in enumerate(xlist):
xlist[index] = item*5
The other problem is even if your items were all unique and the index returned was correct, using .index in a loop is unnecessarily making your algorithm quadratic time, since .index takes linear time.
The index method returns the index of the first occurrence of the item you have passed as an argument (assuming it exists). So, by the time you reach the last element, i.e. 5 at index 4, the item at index 0 is also 5, so you get 5 * 5 at index 0 in the final result.
When the index method is searching for the 5th number (5) it locates the first index that has that value. At this point in time, index 0 (the 1st number) is also 5 so it multiplies index 0 by 5. A better way to loop through is to use the enumerate method to loop through each index and modify the number at that index, rather than find the index afterwards. This eliminates the troubles with the index method.
xlist=[1,2,3,4,5]
print(xlist)
#loop all items in the lxist
for i, item in enumerate(xlist):
print(item)
#multiply each item by 5
xlist[i] *= 5
#print the list
print(xlist)
Results:
[1, 2, 3, 4, 5]
1
[5, 2, 3, 4, 5]
2
[5, 10, 3, 4, 5]
3
[5, 10, 15, 4, 5]
4
[5, 10, 15, 20, 5]
5
[5, 10, 15, 20, 25]
Related
So I recently gave an online interview for a job. Although my expertise are networks and cyber security.
I came across this question:
Write a function which takes an array of integers and returns the
first covering prefix of that array. The "first covering prefix" of an
array, A, of length N is the smallest index P such that 0 <= P <= N
and each element in A also appears in the list of elements A[0]
through A[P]. For example, the first covering prefix of the following
array: A = [5, 3, 19, 7, 3, 5, 7, 3] is 3, because the elements from
A[0] to A[3] (equal to [5, 3, 19, 7]) contains all values that occur
in array A.
Although I am not a programmer (chose python3 for the interview),
I would like someone to explain the logic behind this.
Just wanting to learn, its been bugging me for a day now.
You can iterate all elements, if not already seen (use a set to keep track efficiently), update P:
A = [5, 3, 19, 7, 3, 5, 7, 3]
S = set()
P = 0 # you could set -1/None as default to account for empty lists?
for i, item in enumerate(A): # iterate elements together with indices
if item not in S: # if we haven't seen this element yet
P = i # update P as the current index
S.add(item) # add the element to the set
print(P)
output: 3
b=list(map(int,input().split()))
c=max(b)
for i in b:
if i == c:
b.remove(i)
else:
continue
print(max(b))
where I am getting wrong with this code I am not getting correct output for input 6 4 5 6 6
We can use a set and sorted() to grab the second highest number in the list.
Passing your list to a set will only include unique numbers
We then sort the set and grab the second last element in the list
data = [6, 4, 5, 6, 6]
sorted(set(data))[-2]
#5
First Approach
In this code, we are sorting the list b and then printing the second-last value using indexing
b=list(map(int,input().split()))
sorted(b)
print(b[-2])
Output:
6
Second Approach
In this approach, we are sorting the list, converting it to a set to remove duplicate values, converting the set again into a list and getting the second-last value
b=list(map(int,input().split()))
sorted(b)
final_b = list(set(b))
print(final_b[-2])
Output
5
Actually, the above codes can be written in a single line / fewer lines but it won't be easy for you to read if you are a beginner.
b = list(set(map(int, input().split())))
b.sort()
print(None if len(b) < 2 else b[-2])
set is used to delete duplicate values, and finally to determine if there are two numbers.
A different approach would be to use the nlargest method of the heapq module. it can be used to find the first n largest numbers
import heapq
data = [6, 4, 5, 6, 6]
heapq.nlargest(2, set(data)) # returns [6, 5]
# So we can unpack the values as below
_, second_max = heapq.nlargest(2, set(data)) # the '_' means we dont care about storing that variable
# Now print it
print(second_max) # Output: 5
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]]
This question already has answers here:
Python: pop from empty list
(5 answers)
Closed 3 years ago.
N=8
f,g=4,7
indexList = range(N)
print indexList
print f, g
indexList.pop(f)
indexList.pop(g)
In this code I am getting an error stating that the pop index of g in indexList is out of range.
Here is the output:
[0, 1, 2, 3, 4, 5, 6, 7]
4 7
Traceback (most recent call last):
indexList.pop(g)
IndexError: pop index out of range
I don't understand, g has a value of 7, the list contains 7 values, why is it not able to return me the 7 in the list?
To get the final value of a list pop'ed, you can do it this way:
>>> l=range(8)
>>> l
[0, 1, 2, 3, 4, 5, 6, 7]
>>> l.pop(4) # item at index 4
4
>>> l
[0, 1, 2, 3, 5, 6, 7]
>>> l.pop(-1) # item at end - equivalent to pop()
7
>>> l
[0, 1, 2, 3, 5, 6]
>>> l.pop(-2) # one left of the end
5
>>> l
[0, 1, 2, 3, 6]
>>> l.pop() # always the end item
6
>>> l
[0, 1, 2, 3]
Keep in mind that pop removes the item, and the list changes length after the pop. Use negative numbers to index from the end of a list that may be changing in size, or just use pop() with no arguments for the end item.
Since a pop can produce these errors, you often see them in an exception block:
>>> l=[]
>>> try:
... i=l.pop(5)
... except IndexError:
... print "sorry -- can't pop that"
...
sorry -- can't pop that
After you pop the 4, the list only has 7 values. If you print indexList after your pop(f), it will look like:
[0, 1, 2, 3, 5, 6, 7]
Along with all the other answers, the important part about the pop() function is that it removes the value from the array, thus changing the indexes. After popping index 4, your list is left with 7 items. It is important to know that Python indexes starting at 0 so your 7 item list only contains indexes 0 through 6. That's why popping index 7 is out of bounds, it no longer exists.
Typically a "popping" function is used when implementing a stack or a queue where the goal is to get a value from a list of values waiting to be processed. To avoid processing the same data twice by accident, you make sure to remove it at the same time as retrieval.
Sometimes stacks and queues can be implemented with a peek operation that will return just the value without removing it but since Python implements stacks and queues just using regular arrays without any special wrapper, your peek function would be the standard array[index] call.
----EDIT----
It occurs to me that it could be the case that instead of removing the item at index 7, you wish to remove the value 7. If that's the case, you should call indexList.remove(7). This will remove the first instance of 7 in your list, no matter what its index (and throws an error if there is no value 7). I'm pretty sure you understand that pop() takes an index, though.
Just in case, take a look at the Python datastructures API for more information on what functions are available, what they do, and what arguments they take.
I'm reading some books on Python, data structures, and analysis and design of algorithms. I want to really understand the in's and out's of coding, and become an efficient programmer. It's difficult to ask the book to clarify, hence my question on stackoverflow. I'm really finding Algorithms and recursion challenging ... I posted some code (insertion sort) below that I'm trying to understand exactly what's happening. I understand, generally, what is supposed to happen, but I'm not really getting the how and why.
From trying to analyze pieces of the code on Python Idle, I know that:
key (holds variables) = 8, 2, 4, 9, 3, 6
and that:
i (holds the length) = 7 ( 1, 2, 3, 4, 5, 6, 7)
I don't know why 1 is used in the first line: range(1, len(mylist)). Any help is appreciated.
mylist = [8, 2, 4, 9, 3, 6]
for j in range(1,len(mylist)):
key = mylist[j]
i = j
while i > 0 and mylist[i-1] > key:
mylist[i] = mylist[i - 1]
i -= 1
mylist[i] = key
Let me try to break this down.
Start by considering a list. It is "almost" sorted. That is, the first few elements are sorted, but the last element is not sorted. So it looks something like this:
[10, 20, 30, 50, 15]
Obviously, the 15 is in the wrong place. So how do we move it?
key = mylist[4]
mylist[4] = mylist[3]
mylist[3] = key
That'll switch around the 15 and the 50 so now the list looks like:
[10, 20, 30, 15, 50]
But we'd like to do this several times in a loop. To do that we can do:
while ???:
key = mylist[i]
mylist[i] = mylist[i-1]
mylist[i-1] = key
i -= 1
That loop will go back one position at a time swapping the two elements. That'll move the out of order position one place back each time. But how do we know when to stop?
Let's look again at our list and the moves we want to make:
[10, 20, 30, 50, 15]
[10, 20, 30, 15, 50]
[10, 20, 15, 30, 50]
[10, 15, 20, 30, 50]
# stop! we are sorted now!
But what is different that last time around? Every time we move the number one place back, it is because the 15 is less then the element on the left, meaning its not sorted. When that is no longer true we should stop moving. But we can easily deal with that:
key = mylist[i]
while key < mylist[i-1]:
mylist[i] = mylist[i-1]
mylist[i-1] = key
i -= 1
Ok, but happens if we now try to sort this list:
[10, 20, 1]
[10, 1, 20]
[1, 10, 20]
# ERROR!!
At this point something bad happens. We try to check whether key < mylist[i-1] but when we've reached the beginning, i = 0, and this checks the end of the list. But we should stop moving to left at this point...
If we reach the beginning of the list, we can't move our pivot/key further so we should stop. We update our while loop to handle that:
key = mylist[i]
while i > 0 and key < mylist[i-1]:
mylist[i] = mylist[i-1]
mylist[i-1] = key
i -= 1
So now we have a technique for sorting an almost sorted list. But how can we use that to sort a whole list? We sort parts of the list at a time.
[8, 2, 4, 9, 3, 6]
First we sort the first 1 elements:
[8, 2, 4, 9, 3, 6]
Then we sort the first 2 elements:
[2, 8, 4, 9, 3, 6]
Then we sort the first 3 elements
[2, 4, 8, 9, 3, 6]
So on and so forth
[2, 4, 8, 9, 3, 6]
[2, 4, 8, 9, 3, 6]
[2, 3, 4, 8, 9, 6]
[2, 3, 4, 6, 8, 9]
But how do we do we do that? With a for loop
for j in range(len(mylist)):
i = j
key = mylist[i]
while i > 0 and key < mylist[i-1]:
mylist[i] = mylist[i-1]
mylist[i-1] = key
i -= 1
But we can skip the first time through, because a list of one element is obviously already sorted.
for j in range(1, len(mylist)):
i = j
key = mylist[i]
while i > 0 and key < mylist[i-1]:
mylist[i] = mylist[i-1]
mylist[i-1] = key
i -= 1
A few minor changes which make no difference brings us back to your original code
for j in range(1, len(mylist)):
key = mylist[j]
i = j
while i > 0 and key < mylist[i-1]:
mylist[i] = mylist[i-1]
i -= 1
mylist[i] = key
The insertion sort algorithm works by trying to build up a sorted list of increasing length at the start of the array. The idea is that if you start off by building a one-element sorted list at the beginning, then a two-element list, then a three-element list, etc., that once you've built up an n-element sorted list, you have sorted the entire array and are done.
For example, given the array
3 1 4
We can split this into a zero-element sorted list and a three-element unsorted list:
| 3 1 4
Now, we add 3 to our sorted list. Since that list is now only one element long, it's automatically sorted:
3 | 1 4
Now, we want to add 1 to our sorted list. If we just add 1 to the end of the list like this:
3 1 | 4
then the sorted list is no longer sorted. To fix this, the inner loop of the insertion sort code works by continuously swapping the 1 with the element before it until it's in the proper position. In our case, we swap the 1 and the 3:
1 3 | 4
and since the 1 is now at the beginning of the array, we don't need to move it any more. This is why the inner loop runs while i > 0; once the index of the new element (i) is at the start of the array, there's nothing before it that could be any bigger.
Finally, we update the array by adding 4 to the sorted list. Since it's in sorted position, we're done:
1 3 4
And our array is now in sorted order.
Now, to your original question: why does the outer loop start at 1? This is a cute optimization trick. The idea is that any one-element array must automatically be sorted. This means that the algorithm can start off by saying that the first element of the array is a one-element sorted list. For example, given the array
2 7 1 8
The insertion sort algorithm could try splitting this array like this, putting an empty sorted list at the front:
| 2 7 1 8
But a marginally faster option is to split the list like this:
2 | 7 1 8
which is guaranteed to be safe because any one-element list is automatically sorted.
This is really an optimization of the algorithm on the part of the authors. The algorithm would work perfectly fine if the outer loop started at zero, but they've just decided to start it at one to avoid an unnecessary loop iteration.
Hope this helps!
Have a look at the while loop. It starts with i having the value of 1, but then i is decreased. So in the last line, the minimum value of i could be 0, which is the first element in the list. If you would start with 0, i would become -1 which is valid in python, but means the last element. Therefore the range has to start with 1.
I would like to mention, that you are asking for insertion sort. I don't thin that your code implements insertion sort. Looks rather like bubble sort or something like that.
The reason is that:
i = j
and that mylist is accessed like:
mylist[i - 1]
Therefor the first value is 0. If the range would have started at 0, it would cause an mylist to be accessed at position -1.
Check out animated InsertionSort HERE
Later on i = j is set, and and myList[i-1] is accessed. So, j must be j >= 1.
Added: setting j = 0 is logicaly wrong because in the loop myList[j-1] is accessed - this is just by doing statical analysis of the code (and knowing i = j). Even if this cannot happen during runtime because of while i > 0, it is at least meaningless. If the expression myList[j-1] appears in the code, then it must surely be j >= 1.
The j-the iteration inserts the j-th element into the sorted elements before j. So it makes no sense to start with j=0. In the case j=1 the sublist below is myList[0:1] which is allways sorted, and the loop inserts myList[1] into the sublist myList[0:2]