So, I used to program in python a bit (in school) but I am recently getting back into it. I have two different for loops, one that I did myself (which doesn't work and is hashed out) and one that works (on the line above it).
I was wondering why the hashed out code doesn't work within the bubble sort function, it still loops the same number of times but for some reason when counting up the loop, the 99 will slowly move all the way to the end. However, when counting down, it completes this in 1 step. Here's the code
import random
unsorted_list = [2, 99, 95, 59, 54, 84, 6, 77, 45, 26]
print("The unsorted list is given as = ",unsorted_list)
def Bubble_sort(random_list):
Len_list = len(random_list)
for pass_number in range(Len_list-1,0,-1):
#for pass_number in range(0,Len_list,1):
print(pass_number)
print(random_list)
for A in range(pass_number):
if random_list[A] > random_list[A+1]:
temp = random_list[A]
random_list[A] = random_list[A+1]
random_list[A+1] = temp
Bubble_sort(unsorted_list)
Screenshots of my results running the two different loops separately can be seen below at links 1 & 2. Link 1 is counting down (correct way) and link 2 shows counting up (incorrect results) but I don't know why they are incorrect.
My question is why doesn't it work both ways??
Thank you for helping!
Extra info = This was in python 3.9.0
Only one of your outer loops overlaps properly with your inner loop.
That inner loop has one clear function: it walks the largest value down to position pass_number, one swap at a time. Any other progress is a by-product; the critical outcome is that largest element.
When you start with pass_number at the end of the list (actually, one short: A+1 is the end), the program works just fine: the first pass moves 99 to the end; the next moves 95 next to it, and so on.
It's important to note the opposite movement: a small value can only move to the left one position on each pass.
When you reverse only one loop, what you now have is a combination that will get some of the work correct, but is almost guaranteed to fail. You don't touch the last element in the list until the final iteration; unless that last element happens to be one of the two largest, it cannot work its way to its proper position. It is consulted only on the final iteration.
If you want to reverse the process, fine -- do so. When you reverse the counting on pass_number, you also must reverse the restriction on the inner loop, so that the first iteration considers the entire list, in order.
Can you take it from there? Figuring out that inner loop change is a good intro exercise.
Related
I'm new to programming and data structures and algorithms. I understand the program, what I don't understand is why does it recursively do what I want? I guess what I'm asking is why doesn't it stop after it goes through the list once? It keeps going until the whole list is sorted.
def bubblesort(numbers):
for i in range(len(numbers)):
for j in range(len(numbers) - 1):
if(numbers[j] > numbers[j+1]):
temp = numbers[j]
numbers[j] = numbers[j+1]
numbers[j+1] = temp
There are two loops. The inner loop traverses the whole list for every iteration of the outer loop.
Now notice this:
The inner loop will guarantee that the greatest value "bubbles up" -- with every swap in which it participates -- to the far right. So after the first time that this inner loop completes, the greatest value will have arrived in its final spot.
The second time this inner loop restarts, we could imagine the list to be one element shorter: just imagine that the right most (i.e. greatest) value is not there. Then we have a similar situation: the now greatest value is guaranteed to be shifted to the far right. The inner loop will also compare this "greatest" value with the one we ignored (that really sits at the far right), but obviously they will not be swapped. So after the second time this inner loop does its traversal we have the two greatest values at the far right, in their final position.
So, there is a pattern here. If the inner loop is executed (in its totality) 10 times, then at the end we will have the greatest 10 values at the far right. That is why the outer loop makes as many iterations as there are values in the list. This way it is guaranteed that we will have sorted the whole list.
Well, if I've got your question correctly, the point you're trying to understand is why your code run your list multiples time instead of only once right?
You've got a for inside another, in this way, in line 2 you started a loop that will walk trough the number array. For EVERY repetition of the first loop you are doing another loop in line 3, so, every time you run the array on line 2 you're running it again on line 3.
That's one of the main issues with bubble sorting, you'll keep running the array even after it was sorted.
New to Python, this is my first application. I've been staring at this a while, and I'm sure I have some fundamental misunderstanding about what's going on.
In this example I have a list of 7 str (entries), and an assignment statement:
listLen = len(entries)
Followed by a breakpoint, and below is a screen capture showing the debugger where listLen is assigned a value of 1, and entries is a {list: 7}
I'd expect len(entries) to return a value of 7, but I can't seem to get the expected behavior. What am I missing?
UPDATE: I thought the answer was in the for loop modifying the list but apparently not.
If I set a breakpoint before assigning entries and single step through with the debugger including the for loop everything looks good and works.
If I set a breakpoint ON the for loop and single step once, entries again appears to be a {list: 7} but the len(entries) appears to be 1. The for loop executes one loop and exits.
The deep copy entriesCopy I made for debug is used nowhere else, and gets changed to [''], but I assume that since it's not used it gets optimized out or garbage collected, though it doesn't when single-stepping from an earlier breakpoint.
After breaking on the 'for' loop and single stepping once to the beginning of the 'while' loop:
Why would single stepping through the code work fine, but breaking at the for loop cause len(entries) to be wrong?
Single stepping from earlier breakpoint works fine, and the program returns the correct result:
I'm still struggling to get a minimum reproducible sample of code.
Here's more of the code:
entries = self.userQuery.getEntries()
entriesCopy = copy.deepcopy(self.userQuery.getEntries())
entryList = list()
listLen = len(entries)
for ii in range(0,listLen):
while ("\n\n") in entries[ii]: entries[ii]=entries[ii].replace("\n\n","\n") #strip double newlines
while ("\t") in entries[ii]: entries[ii] = entries[ii].replace("\t", "") # strip tabs
entryList=entries[ii].split("\n")
while("" in entryList): entryList.remove('')
self.SCPIDictionary[self.instructions[ii][1].replace("\n","")]=entryList;
Look a little higher in your debug output- you can see on line 42 entries: ['']
I can't read the code in your for loop so I don't know whats happening, but you seem to be modifying the list in there. If you use the "hover" to look at the value, you would get the current value of that variable. You set the breakpoint on the "for" part of the loop- try setting it on the first line of the loop and the line before the loop and watch for that entries list to get mutated.
--- edit ---
You provided more code. Its... kind of insane. Why are you modifying the "entries" object repeatedly in while loops? Then you copy the entry into another object, and then replace a value in some dictionary with the entry you just copied (with the key determined after running string transformations on a matrix dictionary?)
Two things-
To debug this, I am concerned about the types. Does "getEntries" actually return a list of strings, or is it a resultproxy or something similar? Sqlalchemy for example does not actually return a list. The python debugger is great, but you're doing so much mutation here- instead, lets use print statements. do print(entries) after every line. That will let you see when things are changing, and at least how many times your loop is executing. If it is something like a result proxy, as an example, after you finished iterating over it, there may just not be anything left in there when you look at it in the debugger.
consider this- instead of modifying all these mutable objects, pull out the values and modify those. As a rough draft-
for entry in entries:
values = []
for val in entry.replace("\n\n", "\n").replace("\t, "").split("\n"):
if val:
values.append(val)
self.CCPIDictionary[something?] = values
lt = 1000 #list primes to ...
remaining = list(range(2, lt + 1)) #remaining primes
for c in remaining: #current "prime" being tested
for t in remaining[0: remaining.index(c)]: #test divisor
if c % t == 0 and c != t:
if c in remaining:
remaining.remove(c)
If you don't need context:
How can I either re-run the same target-list value, or use something other than for that reads the expression list every iteration?
If you need context:
I am currently creating a program that lists primes from 2 to a given value (lt). I have a list 'remaining' that starts as all integers from 2 to the given value. One at a time, it tests a value on the list 'c' and tests for divisibility one by one by all smaller numbers on the list 't'. If 'c' is divisible by 't', it removes it from the list. By the end of the program, in theory, only primes remain but I have run into the problem that because I am removing items from the list, and for only reads remaining once, for is skipping values in remaining and thus leaving composites in the list.
What you're trying to do is almost never the right answer (and it's definitely not the right answer here, for reasons I'll get to later), which is why Python doesn't give you a way to do it automatically. In fact, it's illegal for delete from or insert into a list while you're iterating over it, even if CPython and other Python implementations usually don't check for that error.
But there is a way you can simulate what you want, with a little verbosity:
for i in range(remaining.index(c)):
if i >= remaining.index(c): break
t = remaining[i]
Now we're not iterating over remaining, we're iterating over its indices. So, if we remove values, we'll be iterating over the indices of the modified list. (Of course we're not really relying on the range there, since the if…break tests the same thing; if you prefer for i in itertools.count():, that will work too.)
And, depending on what you want to do, you can expand it in different ways, such as:
end = remaining.index(c)
for i in range(end):
if i >= end: break
t = remaining[i]
# possibly subtract from end within the loop
# so we don't have to recalculate remaining.index(c)
… and so on.
However, as I mentioned at the top, this is really not what you want to be doing. If you look at your code, it's not only looping over all the primes less than c, it's calling a bunch of functions inside that loop that also loop over either all the primes less than c or your entire list (that's how index, remove, and in work for lists), meaning you're turning linear work into quadratic work.
The simplest way around this is to stop trying to mutate the original list to remove composite numbers, and instead build a set of primes as you go along. You can search, add, and remove from a set in constant time. And you can just iterate your list in the obvious way because you're no longer mutating it.
Finally, this isn't actually implementing a proper prime sieve, but a much less efficient algorithm that for some reason everyone has been teaching as a Scheme example for decades and more recently translating into other languages. See The Genuine Sieve of Eratosthenes for details, or this project for sample code in Python and Ruby that shows how to implement a proper sieve and a bit of commentary on performance tradeoffs.
(In the following, I ignore the XY problem of finding primes using a "mutable for".)
It's not entirely trivial to design an iteration over a sequence with well-defined (and efficient) behavior when the sequence is modified. In your case, where the sequence is merely being depleted, one reasonable thing to do is to use a list but "delete" elements by replacing them with a special value. (This makes it easy to preserve the current iteration position and avoids the cost of shifting the subsequent elements.)
To make it efficient to skip the deleted elements (both for the outer iteration and any inner iterations like in your example), the special value should be (or contain) a count of any following deleted elements. Note that there is a special case of deleting the current element, where for maximum efficiency you must move the cursor while you still know how far to move.
I am monitoring a rss feed using feedparser. The feed has 100 items and am extracting a time stamp from it as a unique identifier in the form of a list of strings. This is what a single item looks of the list like:
2017-07-25T20:41:59-04:00
Next, I am doing some python magic with the other data from the feed which is parsed into lists as well (same index, different lists though) to extract the information I want. That part works well, I love it.
Now my problem: after a time delay
import time
time.sleep(60)
I'd like to monitor the feed again and see efficiently if the time stamp was observed before. If so, I'd pass on executing code and wait some more until a uniqe time stamp shows up.
I failed to implement it so far. I thought about making a second list and comparing the two. Each list has 100 items.
New items appear on top of the feed and move down over time. I should be fine if I only run to the first match. Should make the code more efficient then comparing everything.
I'd be happy iif someone could point me towards the solution. I am somewhat stuck whatever I have tried, failed.
Edit:
def compare(feed_id_l, feed_id_check_l):
#compares items in lists and returns the index
for i in range(0, len(feed_id_l)):
for j in range(0, len(feed_id_check_l)):
if feed_id_l[i] == feed_id_check_l[j]:
print('match for id ' + feed_id_l[i])
return i, j
else:
return -1
Works and returns 0, 0 if the first feed item is unchanged.
I will have to figure out what to do with other cases, let's say 0, 6.
Cheers!
Basically, I want to sort numbers without using 'sort'.
what I plan to do is create a new list and put every Min number into it
such as:
for item in List:
if item < (Min):
Min = item
nList.append(Min)
List.remove(Min)
which List is input list, Min=List[0] and nList =[]
How can I use double loop to keep it run?
Your first problem is that it only runs through the list once because… you wrote a for loop that explicitly runs through the list once, and no other loops.
If you want it to run through the list repeatedly, put another loop around it.
For example, since you're removing values from the original list each time through the loop, you could just keep going until you've remove them all, by adding while List: as an outer loop:
while List:
for item in List:
if item < (Min):
Min = item
nList.append(Min)
List.remove(Min)
This will not actually work as-is, but that's because of other flaws in your original logic, not anything new to the while loop.
The first obvious problems are:
You're removing elements from List as you iterate over it. This is illegal and technically anything could happen, but what actually will happen is that your iteration will skip over some of the elements.
You start Min with List[0], despite the fact that this is generally not the minimum. This means at least your first pass will add elements in the wrong order.
Eventually you will reach a point where item >= Min for every item left in List. What happens then? You never move anything over, and just loop forever doing nothing.
What you are doing (apart from logic errors) is still sorting - it's known as heap sort, and it takes O(n log n) time.
If you don't keep the list as a heap, your finding the minimum will be O(n) instead of O(log n), and your sort will run asymptotically as badly as bubble sort - O(n^2).