Get string backwards using for loop, Python - for-loop

I found this previously answered here, Best way to loop over a python string backwards
I need to use OP's original idea, but I don't quite understand the meaning of the stop argument in the range function. What does 0-1 mean? From 0-1? Wouldn't that be the step?

Why can't you use reversed as accepted in the previously answered question?
However, to answer your original question:
The 0-1 is actually just a number 0-1, which is equal to -1
The documentation for range says the following: range(start[, end[, step]]). His call looks like the following: range(len(string)-1, 0-1, -1)
start = len(string)-1, which is last letter of the string.
end = 0-1 which is equal to -1, so the last letter being handled is 0. Remember that range(0, 3) will actually give 0, 1, 2 and stop right before the 3. Same goes for negative numbers, it will stop right before -1, so it will stop at 0.
step = -1. Step stands for how many numbers to step over at once. -1 means it will lower i by one every time.

The 0-1 is -1, it can be written either way:
>>> -1
-1
>>> 0-1
-1
Let's try a string length of 10, stop of 0-1 ad step of -1:
>>> range(10, 0-1, -1)
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
you'll see the same result with -1 instead of 0-1:
>>> range(10, -1, -1)
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
The step of -1 causes range to count backward, let's try a step of 1:
>>> range(10, 0-1, 1)
[]
When in doubt, shell it out

Related

What does this line mean in Sorting Algo(Bubble example)

def bubbleSort(array):
swapped = False
for i in range(len(array)-1,0,-1):
print(i)
for j in range(i):
print(j)
if array[j]>array[j+1]:
array[j], array[j+1] = array[j+1], array[j]
swapped= True
if swapped:
swapped=False
else:
break
print(array)
bubbleSort([5, 2, 1, 3])
How should I interpret this line: for i in range(len(array)-1,0,-1)? I'm particularly confused about the need for the 0 and -1 parameters.
That line has a couple of things happening, which I will give simplified explanations of (I'm assuming this code is written in Python).
First, for i in iterable will loop through iterable, meaning the code in the for loop will repeat as many times as there are elements in iterable, which could be an array, a list, a string etc, and each time it loops, i will be the next element of iterable, starting with the first. For example, for i in [1, 2, 3] will loop 3 times; the first time, i will be equal to 1; the second, 2, etc.
Next, the range function produces an iterable that is a range of numbers, for example from 0-9. With a single argument, range will produce a range from 0 to that number, but stopping just before it, e.g. range(5) will give you [0, 1, 2, 3, 4]. Thus if you were to use for i in range(5), your code would repeat 5 times, with i incrementing from 0 to 4.
With two arguments, the range will start at the first and stop before the second, which must be greater than the first. For example, range(3, 8) would give you [3, 4, 5, 6, 7]. range(8, 3), however, will not work, as the start number is greater than the stop number. This means you cannot count down with only 2 arguments.
The third optional argument for range is the step size; how much you want the numbers to increase or decrease by each step. For example, range(0, 10, 2) will give you the output [0, 2, 4, 6, 8], stopping before 10. Here is where you can produce a descending range, by setting the step argument to a negative number. range(10, 0, -2) will give you [10, 8, 6, 4, 2], again stopping before the second argument, and range(10, 0, -1) will give you the full [10, 9, 8, 7, 6, 5, 4, 3, 2, 1].
Finally, the len(iterable) function will give you the length of whatever you give it, or the number of items contained in say a list. For example len("Hello!") will give you 6, and len([1, 2, 3, 4, 5]) will give you 5.
Putting this all together, the line for i in range(len(array)-1, 0, -1) will do the following:
the code will repeat as many times as there are items in a list, with i taking on each value in the list
that list is a range of numbers
that start number of the range is the length of array minus one
the end of the range is 0
the range is descending, with a step size of -1
Thus if array were ["fish", "banana", "pineapple", "onion"], len(array) will return 4, so you will have for i in range(3, 0, -1), which will loop 3 times, with i being 3, then 2, then 1.
This was a rather simplified answer, so I suggest you find some tutorials on any functions you don't understand.

How is this obscure sorting algorithm called

I came up with an obscure sorting algorithm and given that it's so simple, it must have been invented and named before, so I was wondering what it's called.
It has a very rare constraint: It only works for inputs that have keys from 0 to n-1 (or equivalent). That's a very strong constraint that makes it useless in practice, but maybe one can construct some artificial settings in which it's useful. The algorithm basically swaps the element at a particular position with its final position until the array is sorted. Pseudocode:
def obscure_sort(array):
sorted_until = 1
while true
if key(array[0]) != 0:
# Swap the element at position 0 to its final position.
swap(array, 0, key(array[0]))
else:
# Find the next element that isn't in its final position.
while key(array[sorted_until]) == sorted_until:
sorted_until++
# If we happen to reach the end, we're done.
if sorted_until == array.length:
return
# Swap the newfound first unsorted element to position 0
swap(array, 0, sorted_until)
The algorithm actually runs in O(n). It's not completely trivial to see that and I'll leave out the analysis unless someone is really interested.
Does anyone know if this has a name?
This is a slight variation of a restricted cycle sort, probably closest to the algorithm from section 3 of this paper.
Normally with cycle sort on the keys A = [0, 1,...(A.length-1)], you would loop through the array testing indices 0 to A.length-1 as a 'cycle start', looking for cycles to rotate. One 'rotation' is done by always holding a temporary variable 'temp' (initially our cycle start), and doing a swap(temp, A[temp]) until we are back at the start of the cycle (i.e., when temp == A[temp]).
Here, in contrast, we add 0 at the back of the cycle, and 'A[0]' takes the place of 'temp'. We use the operation swap(A[0], A[A[0]]), so that in general, an element x that's moved takes a journey of A[old] -> A[0] -> A[x] rather than A[temp] -> temp -> A[x].
In the linear time algorithm described in the paper above, upon starting loop iteration i, all of the elements 0, 1, ..., i-1 are in place and never moved again. This algorithm is similar, except that if it were written with the same loop style, 0, 1, ..., i-1 are also in place at the start of iteration i but element 0 is not fixed, being moved constantly during an iteration.
As a small example:
Traditional Cycle Sort
Initially, A = [1, 3, 0, 2]
Step 1: A = [1, 3, 0, 2], temp = 1, with cycle_start = 0
Step 2: A = [1, 1, 0, 2], temp = 3
Step 3: A = [1, 1, 0, 3], temp = 2
Step 4: A = [2, 1, 2, 3], temp = 0
Step 5: A = [0, 1, 2, 3], temp = 2; stop since temp == A[temp]
Custom Cycle-like Sort
A = [1, 3, 0, 2]
Step 1: A = [1, 3, 0, 2]
Step 2: A = [3, 1, 0, 2]
Step 3: A = [2, 1, 0, 3]
Step 4: A = [0, 1, 2, 3]
Note that this new sort can take more steps than the normal cycle sort, since 'adding 0 at the back of the cycle' can add an additional swap operation per cycle. The total number of array swaps, though, is linear (and at most twice the array length).

Detect outlier in repeating sequence

I have a repeating sequence of say 0~9 (but may start and stop at any of these numbers). e.g.:
3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2
And it has outliers at random location, including 1st and last one, e.g.:
9,4,5,6,7,8,9,0,1,2,3,4,8,6,7,0,9,0,1,2,3,4,1,6,7,8,9,0,1,6
I need to find & correct the outliers, in the above example, I need correct the first "9" into "3", and "8" into "5", etc..
What I came up with is to construct a sequence with no outlier of desired length, but since I don't know which number the sequence starts with, I'd have to construct 10 sequences each starting from "0", "1", "2" ... "9". And then I can compare these 10 sequences with the given sequence and find the one sequence that match the given sequence the most. However this is very inefficient when the repeating pattern gets large (say if the repeating pattern is 0~99, I'd need to create 100 sequences to compare).
Assuming there won't be consecutive outliers, is there a way to find & correct these outliers efficiently?
edit: added some explanation and added the algorithm tag. Hopefully it is more appropriate now.
I'm going to propose a variation of #trincot's fine answer. Like that one, it doesn't care how many outliers there may be in a row, but unlike that one doesn't care either about how many in a row aren't outliers.
The base idea is just to let each sequence element "vote" on what the first sequence element "should be". Whichever gets the most votes wins. By construction, this maximizes the number of elements left unchanged: after the 1-liner loop ends, votes[i] is the number of elements left unchanged if i is picked as the starting point.
def correct(numbers, mod=None):
# this part copied from #trincot's program
if mod is None: # if argument is not provided:
# Make a guess what the range is of the values
mod = max(numbers) + 1
votes = [0] * mod
for i, x in enumerate(numbers):
# which initial number would make x correct?
votes[(x - i) % mod] += 1
winning_count = max(votes)
winning_numbers = [i for i, v in enumerate(votes)
if v == winning_count]
if len(winning_numbers) > 1:
raise ValueError("ambiguous!", winning_numbers)
winning_number = winning_numbers[0]
for i in range(len(numbers)):
numbers[i] = (winning_number + i) % mod
return numbers
Then, e.g.,
>>> correct([9,4,5,6,7,8,9,0,1,2,3,4,8,6,7,0,9,0,1,2,3,4,1,6,7,8,9,0,1,6])
[3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2]
but
>>> correct([1, 5, 3, 7, 5, 9])
...
ValueError: ('ambiguous!', [1, 4])
That is, it's impossible to guess whether you want [1, 2, 3, 4, 5, 6] or [4, 5, 6, 7, 8, 9]. They both have 3 numbers "right", and despite that there are never two adjacent outliers in either case.
I would do a first scan of the list to find the longest sublist in the input that maintains the right order. We will then assume that those values are all correct, and calculate backwards what the first value would have to be to produce those values in that sublist.
Here is how that would look in Python:
def correct(numbers, mod=None):
if mod is None: # if argument is not provided:
# Make a guess what the range is of the values
mod = max(numbers) + 1
# Find the longest slice in the list that maintains order
start = 0
longeststart = 0
longest = 1
expected = -1
for last in range(len(numbers)):
if numbers[last] != expected:
start = last
elif last - start >= longest:
longest = last - start + 1
longeststart = start
expected = (numbers[last] + 1) % mod
# Get from that longest slice what the starting value should be
val = (numbers[longeststart] - longeststart) % mod
# Repopulate the list starting from that value
for i in range(len(numbers)):
numbers[i] = val
val = (val + 1) % mod
# demo use
numbers = [9,4,5,6,7,8,9,0,1,2,3,4,8,6,7,0,9,0,1,2,3,4,1,6,7,8,9,0,1,6]
correct(numbers, 10) # for 0..9 provide 10 as argument, ...etc
print(numbers)
The advantage of this method is that it would even give a good result if there were errors with two consecutive values, provided that there are enough correct values in the list of course.
Still this runs in linear time.
Here is another way using groupby and count from Python's itertools module:
from itertools import count, groupby
def correct(lst):
groupped = [list(v) for _, v in groupby(lst, lambda a, b=count(): a - next(b))]
# Check if all groups are singletons
if all(len(k) == 1 for k in groupped):
raise ValueError('All groups are singletons!')
for k, v in zip(groupped, groupped[1:]):
if len(k) < 2:
out = v[0] - 1
if out >= 0:
yield out
else:
yield from k
else:
yield from k
# check last element of the groupped list
if len(v) < 2:
yield k[-1] + 1
else:
yield from v
lst = "9,4,5,6,7,8,9,0,1,2,3,4,8,6,7,0,9,0,1,2,3,4,1,6,7,8,9,0,1,6"
lst = [int(k) for k in lst.split(',')]
out = list(correct(lst))
print(out)
Output:
[3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2]
Edit:
For the case of [1, 5, 3, 7, 5, 9] this solution will return something not accurate, because i can't see which value you want to modify. This is why the best solution is to check & raise a ValueError if all groups are singletons.
Like this?
numbers = [9,4,5,6,7,8,9,0,1,2,3,4,8,6,7,0,9,0,1,2,3,4,1,6,7,8,9,0,1,6]
i = 0
for n in numbers[:-1]:
i += 1
if n > numbers[i] and n > 0:
numbers[i-1] = numbers[i]-1
elif n > numbers[i] and n == 0:
numbers[i - 1] = 9
n = numbers[-1]
if n > numbers[0] and n > 0:
numbers[-1] = numbers[0] - 1
elif n > numbers[0] and n == 0:
numbers[-1] = 9
print(numbers)

Find local min based on the length of occurences of successive means without falling in wrong min

1. Problem description
I have the following list of values [10, 10, 10, 10, 5, 5, 5, 5, 7, 7, 7, 2, 4, 3, 3, 3, 10] It is shown in the following picture.
What I want to do is find the minimum based on the value of the element and
its duration. From the previous list we can construct the following dictionary (key:val) :[10:4, 5:4, 7:2, 2:1, 4:1, 3:3, 10:1]. Meaning we have 4 sucessive 10s followed by 4 successive 5s, 2 successive 7s and 3 successive 3s.
Based on what I said the local min is 5. But I don't want that The local min should be 3. We didn't select 2 because it happened only once.
Do you have an idea on how we can solve that problem. Is there an existing method that can be used to solve it?
Of course we can sort the dictionary by values [10:4, 5:4, 7:2, 3:3, 10:1] and select the lowest key that has a value different than 1. Is that a good solution?
2. Selection criteria
must be a local min (find_local_min(prices))
must have the highest numbers of succession
the min succession must be > 1
AND I AM STUCK! because now I have 3 as local minimum but it is repeated only 3 times. I was testing if My idea is correct and I tried to find a counter example and I shot my foot
3. source code
the following code extracts the minimums with the dictionary:
#!/usr/bin/env python
import csv
import sys
import os
from collections import defaultdict
def find_local_min(prices):
i = 1
minPrices = []
while i < len(prices):
if prices[i] < prices[i-1]:
minPrices.append(prices[i])
j = i + 1
while j < len(prices) and prices[j] == prices[j-1]:
minPrices.append(prices[j])
j += 1
i = j
else:
i += 1
return minPrices
if __name__ == "__main__":
l = [10, 10, 10, 10, 5, 5, 5, 5, 7, 7, 7, 2,4, 3, 3, 3, 10]
minPrices = find_local_min(l)
minPriceDict = defaultdict(int)
for future in minPrices :
minPriceDict[future] += 1
print minPriceDict
As output if gives the following: defaultdict(<type 'int'>, {2: 1, 3:
3, 5: 4}) Based on this output the algorithm will select 5 as the min
because it is repeated 5 successive times. But that's wrong! it
should be 3. I really want to know how to solve that problem

Algorithm for generating sequence denoting the sequence of removal of numbers

Given a finite sequence of numbers, in each round, any number whose left neighbour is smaller than itself will be removed. This removal action will continue until nothing can be removed. Each number removed will be labelled with the round it was removed, or 0 if it is never removed.
For example, consider the sequence
0 9 8 7 9 8 7 5
After first round, it becomes,
0 8 7 8 7 5
and after consecutive 4 rounds,
0 7 7 5
0 7 5
0 5
0
Thus the corresponding labels for the numbers are
0 1 2 3 1 2 4 5
How may I generate the sequence of labels in O(N) time by using a stack or queue, when N is the length of the sequence offered? Or may I know the maximum rounds of removing in O(N) time?
Yes it can be done using a single stack, I will describe the solution, and briefly explain why it works later.
Assume the array is A = [0, 9, 8, 7, 9, 8, 7, 5], Ans = [] be the array of corresponding answer. We also maintain an initially empty stack S. The stack will store pairs {A[i], Ans[i]} and we will try to preserve the stack so that it is always strictly increasing on A[i] as follows:
Push {A[0], 0} to S
Loop through array A. For an instance of iteration, let A[i] be current number (Ans[i] not known yet):
2a. Initialize a variable round_to_wait = 0, keep popping the stack S until the top element is smaller than A[i], set rount_to_wait to maximum Ans[x] meanwhile
2b. If the S is empty, then set Ans[i] = 0, else set Ans[i] = round_to_wait + 1
2c. Push {A[i], Ans[i]} to S
Let's do an demo based on your example:
A = [0, 9, 8, 7, 9, 8, 7, 5], Ans = [0, -1, -1, -1, -1, -1, -1, -1], S = [{0,0}]
A[1] = 9 and S.top() already smaller than 9, no element is popped. Ans[1] = round_to_wait + 1 = 0 + 1 = 1, push {9, 1} into S
A = [0, 9, 8, 7, 9, 8, 7, 5], Ans = [0, 1, -1, -1, -1, -1, -1, -1], S = [{0,0}, {9,1}]
A[2] = 8 and we popped element until {0,0} is left. rount_to_wait = 1 as it is the maximum in whole popping process. Ans[2] = round_to_wait + 1 = 1 + 1 = 2, push {8, 2} into S
A = [0, 9, 8, 7, 9, 8, 7, 5], Ans = [0, 1, 2, -1, -1, -1, -1, -1], S = [{0,0}, {8,2}]
Similarly, S = [{0,0}, {7,3}]
Similarly, S = [{0,0}, {7,3}, {9,1}]
Similarly, S = [{0,0}, {7,3}, {8,2}]
Similarly, S = [{0,0}, {7,4}]
Similarly, S = [{0,0}, {5,5}]
And that's it, you have the answer in one loop. As each element at most be pushed and popped one time, the complexity is still O(N)
Why it works is because, Let A[i] be the first element which does not form strictly increasing sequence with S, what does that mean?
That means that, at some point, the top element in S S_top will "block" us from removing A[i]. We have chances (not sufficient condition though) to remove A[i] only if S_top is removed, which means it is at least as soon as Ans[S_top] + 1, and we take the maximum among all such elements.
The special case is that, there is no element smaller than A[i] at all, which means S will eventually be empty, in such case Ans[i] = 0
(PS: I thought I have some memory on this problem on some online judge a few years ago, if that's the source, may you post it out so that I can go and submit to verify the solution?)

Resources