Related
I am new in CS, and I have a really hard task to do. This t h i n g scares me.
During selection sort we can acquire swap distances -- difference between (index value of element in unsorted array) and (index value of element in sorted array). We can find it for example like this (here is the sum of swap distances(code written by myself, calculating sum of swap distances was my previous task), but we can easily obtain a list of swap distances):
x = [int(i) for i in input().split()]
def sel_sort(a):
swap_dist_sum = 0
for i in range(len(a)):
min_idx = i
for j in range(i+1, len(a)):
if a[min_idx] > a[j]:
min_idx = j
a[i], a[min_idx] = a[min_idx], a[i]
swap_dist_sum += (min_idx - i) # new index in sorted list - index from unsorted list
return swap_dist_sum # for each element
print(sel_sort(x))
This was only the intro(this definition is rare).
I have (n - 1) numbers which are swap distances; 1st element from 1st sort iteration, 2nd from 2nd and so on. I have to restore original order of elements in unsorted array of n elements.
I have no idea what I should do. Maybe you can advice me to find/read/use library/little code hints/etc.
Sample Input: # swap distances
1 3 0 1
Sample Output: # original list
4 1 3 5 2
My first steps should be like this:
swap_dist_l = [int(i) for i in input().split()] # list containing all swap distances
sorted_l = [i for i in range(1, len(swap_dist_l) + 2)] # already sorted list
As a result, I should have unsorted_l with original unsorted order of elements.
Sorry if my speech is hard to understand!
P.S. I didn't find any similar/duplicate questions. Pls send a link if I'm bad at searching!
You should perform the swaps that correspond to the swap distances you get, but in reversed order, so starting from the right:
def unsort(data_l, swap_dist_l):
for i, dist in reversed(list(enumerate(swap_dist_l))):
# swap
data_l[i+dist], data_l[i] = data_l[i], data_l[i+dist]
Call as follows for the example given:
swap_dist_l = [1, 3, 0, 1]
data_l = [i for i in range(1, len(swap_dist_l) + 2)] # [1, 2, 3, 4, 5]
unsort(data_l, swap_dist_l)
print(data_l) # [4, 1, 3, 5, 2]
Lets look at how selection sort works for a simple list lst = [3,1,2]:
We first look at index 0 and find the smallest element which is 1 at index 1.
We then swap these, i.e. lst[0], lst[1] = lst[1], lst[0]
Then we look at index 1 and find the smallest element which is 2 at index 2.
We then swap these, i.e. lst[1], lst[2] = lst[2], lst[1]
Now the list is sorted and we have a list of swap distances swap_dst = [1,1]
In order to restore the list we then need to reverse the swaps we did to get it sorted or in other words we need to do the same swaps again but in reversed order.
lst = [1,2,3]
lst[1], lst[2] = lst[2], lst[1]
lst[0], lst[1] = lst[1], lst[0]
print(lst) # [3,1,2]
So what you need to do is find out how to use the swap distances to find what swaps were made and do those swaps again.
I would like to know how to find the nth term - (n-1)th term within a list. I know it should be very simple, but I'm just having trouble with application. So given the input of [0, 2, 4, 6, 5], the function should return [0, 2, 2, 2, -1]. My solution (which doesn't work) is as follows:
def cost_to_diff (stocks):
for i in range(i+1):
stock[i] = stock[i] - stock[i-1]
print stock
Why doesn't this work as intended?
Your mistake is that you reset the ith element of list, so on the next cycle iteration you access it's changed value.
This will print what you need
def cost_to_diff (stocks):
for i in range(1, len(stocks)):
print stocks[i] - stocks[i-1]
If you want to print a list, then do
def cost_to_diff (stocks):
diff = []
for i in range(1, len(stocks)):
diff.append(stocks[i] - stocks[i-1])
print diff
or
def cost_to_diff (stocks):
print [stocks[i] - stocks[i-1] for i in range(1, len(stocks))]
Also I advice you to try numpy for such tasks. This function will do the job. Especially if you are playing with stock data, numpy will be much faster than lists. Moreover for stock data one usually uses data frames, so pandas is what you need to study, and Series.diff is the function you need.
You are using the wrong range. You need to find out the length of the stocks list, and then build your range accordingly.
differences = []
for i in range(len(stocks) - 1):
differences.append(stock[i+1] - stock[i])
print differences
However, there is a better way to do this. Python has several builtins to help you do this kind of stuff easily. Use the zip function to get your elements without messing around with indexes.
differences = []
for a, b in zip(l, l[:1]):
differences.append(b-a)
For example:
my_list = [0, 3, 4, 5, 7]
print zip(my_list, my_list[1:])
This produces output
[(0, 3), (3, 4), (4, 5), (5, 7)]
All you need to do after is subtract the elements.
The following code returns [2, 2, 2, -1] because I don't get why you will get 0 for the first element.
Do you assume that the first -1 element is also 0?
len('list') will give you the length of list.
range(start, end) will give you a range.
Since you like to start your iterations in the for loop at the second element (index = 1) start will be 1 and end will be the length of the stock list.
stock = [0,2,4,6,5]
result = []#create an empty list for the results
for i in range(1,len(stock)):#set the iteration steps, will be 1,2,3,4 in this case
result.append(stock[i] - stock[i-1])#By using stack[i] = ... you will overwrite the ith element
print result
I've got a list of numbers, e.g.:
l=[0.01,0.02,0.01,-0.01,0,0,0,0,0,0,0,0,0,0]
What I want to know is, how many leading values do I need to drop to get a list of all zeros?
So the answer here is 4.
I'm thinking, reverse the list, then use a for loop and a counter to run down the list until I find the first non-zero element, and then subtract counter and list length, but it seems a bit ugly.
Is there a nice 'pythonic' way to do it?
(Edit for clarity:
l=[0.01,0.02,0.01,-0.01,0,0,0,0,0,0,1,0,0,0]
should go to 11, so I can't just use filter. I want to know how long the producer took to settle down to the point where the output becomes continuously zero)
You can use itertools.dropwhile and itertools.takewhile for this:
>>> l = [0.01,0.02,0.01,-0.01,0,0,0,0,0,0,0,0,0,0]
>>> import itertools
>>> list(itertools.dropwhile(lambda x: x != 0, l))
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> list(itertools.takewhile(lambda x: x != 0, l))
[0.01, 0.02, 0.01, -0.01]
>>> sum(1 for _ in itertools.takewhile(lambda x: x != 0, l))
4
However, if you want the list to contain only 0, then dropping from the front might not work if there are zeros and then non-zero elements again. Instead, you might better start from the end, using reversed, until you find the first non-zero element.
>>> sum(1 for _ in itertools.takewhile(lambda x: x == 0, reversed(l)))
10
>>> sum(1 for _ in itertools.dropwhile(lambda x: x == 0, reversed(l)))
4
Here, the first is the number of consecutive zeros starting from the end of the list, and the second the number of the remaining elements starting with the first non-zero, again from the end.
point = next(index for index, value in enumerate(reversed(l)) if value != 0)
point = len(l) - point if point else -1
We iterate over the list in reversed order till we get the first non 0 element. We use that index and subtract it from length to get the actual point.
updated code as suggest in comment.
Thanks tobias_k
There isn't a particularly Pythonic and efficient way to do this. You could iterate backwards over the list using range, but I think it's slightly cleaner to use the reversed list iterator:
def nonzeros(seq):
for i, v in enumerate(reversed(seq)):
if v:
break
return len(seq) - i
lst = [0.01,0.02,0.01,-0.01,0,0,0,0,0,0,0,0,0,0]
print(nonzeros(lst))
lst = [0.01,0.02,0.01,-0.01,0,0,0,0,0,0,1,0,0,0,0]
print(nonzeros(lst))
output
4
11
Reversing the list is an O(n) operation anyway, so there's no point. Just walk the list and note the index of the last non-zero element.
last = -1
for i, value in enumerate(l):
if value != 0:
last = i
(Consider using a tolerance test instead of strict equality for value.)
After the walk, last + 1 is the index of the first 0 in the longest all-zero suffix of your list. That is, all(x == 0 for x in l[last+1:]) will be true.
How about a verbatim solution, e.g. find the maximal index of a non-zero element?
res = max(i for i, x in enumerate(lst) if x != 0) + 1
pop would make your counting easy:
l=[0.01,0.02,0.01,-0.01,0,0,0,0,0,0,0,0,0,0]
while not l.pop():
pass
result = len(l) + 1
assert result == 4
Edit
I would make it a function though:
def foo(original):
clone = original[:]
while not clone.pop(): pass
return len(clone) + 1
l=[0.01,0.02,0.01,-0.01,0,0,0,0,0,0,0,0,0,0]
assert foo(l) == 4
l=[0.01,0.02,0.01,-0.01,0,0,0,0,0,0,1,0,0,0]
assert foo(l) == 11
The length of the list is stored with its internal data. Start with the length of the full list, and then iterate through the list backwards until you find a non-zero value.
Worst case complexity should be O(n) if the list is all zeros.
It would be lightning fast in the case of a very long list with only a couple of zeros at the end before the first non-zero value, such as my_list = [5] * 1000000 + [0, 0].
my_list = [0.01, 0.02, 0.01, -0.01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
n = len(my_list)
while n:
n -= 1
if my_list[n] != 0:
n += 1
break
>>> n
4
Given:
>>> l=[0.01,0.02,0.01,-0.01,0,0,0,0,0,0,1,0,0,0]
You can use groupby on a reversed iterator of the list to group the value of the last item for as long as that value is == the value before it:
>>> last_grp=next((k, len(l)-sum(1 for _ in v)) for k,v in groupby(reversed(l)))
>>> last_grp
(0, 11)
The first element of the tuple returned will be the repeated value of the last group -- 0 in this case. The length of that group then is how long. Subtract that from the overall list length for the index to the start of the group.
reversed and groupby are iterators. next returns the next value of an iterator. Since this is the last group, it is only needed once. This is efficient on any size list.
This works on a group of anything where l[x-1]==l[x] and the value of k is set to whatever value that is. groupby does just that -- groups items of the same value together.
You could also use groupby to find ranges where some condition is True or False; in this case, created than 0:
di={True:[], False:[]}
for k, v in groupby(enumerate(l), key=lambda t: t[1]>0):
grp=list(v)
di[k].append((grp[0][0], grp[-1][0]))
>>> di
{False: [(3, 9), (11, 13)], True: [(0, 2), (10, 10)]}
So the list l has a value greater than 0 in each range of [(0, 2), (10, 10)] and a value less than or equal to 0 in a range of [(3, 9), (11, 13)]
l = [0.01,0.02,0.01,-0.01,0,0,0,0,0,0,1,0,0,0]
for i,j in enumerate(reversed(l)) :
if j:
print (len(l[:-i]))
break
Output:
11
This is probably more convoluted than you would want it to be but its my 2 cents anyway:
l=[0.01,0.02,0.01,-0.01,0,0,0,0,0,0,1,0,0,0]
s = len(l) - next(i for i, x in enumerate(l[::-1]) if x != 0)
print(s) # 11
Update-> Earlier I misunderstood the question. (Thanks to dawg)
One way can be to convert the reversed list into bool array and search for first non-zero(True) value in the list.
For both operations (converting and searching) we can use built-in functions and thus better speed but it comes at cost of some memory(you haven't mentioned anything about memory consumption,so I'm assuming extra memory is available).
Here's the Code
bool_list = map(bool, reversed(l))
index = bool_list.index(True)
if index == -1:
# No such sub-array found
return len(bool_list)
else:
# Start index of the required sub-array
return len(bool_list) - index
Here, we used reversed instead of slice operator [::-1] for reversing because it is a generator function and returns element on the go without consuming any additional memory. We just need memory for bool array.
I need a function that generates all the permutation with repetition of an iterable with the clause that two consecutive elements must be different; for example
f([0,1],3).sort()==[(0,1,0),(1,0,1)]
#or
f([0,1],3).sort()==[[0,1,0],[1,0,1]]
#I don't need the elements in the list to be sorted.
#the elements of the return can be tuples or lists, it doesn't change anything
Unfortunatly itertools.permutation doesn't work for what I need (each element in the iterable is present once or no times in the return)
I've tried a bunch of definitions; first, filterting elements from itertools.product(iterable,repeat=r) input, but is too slow for what I need.
from itertools import product
def crp0(iterable,r):
l=[]
for f in product(iterable,repeat=r):
#print(f)
b=True
last=None #supposing no element of the iterable is None, which is fine for me
for element in f:
if element==last:
b=False
break
last=element
if b: l.append(f)
return l
Second, I tried to build r for cycle, one inside the other (where r is the class of the permutation, represented as k in math).
def crp2(iterable,r):
a=list(range(0,r))
s="\n"
tab=" " #4 spaces
l=[]
for i in a:
s+=(2*i*tab+"for a["+str(i)+"] in iterable:\n"+
(2*i+1)*tab+"if "+str(i)+"==0 or a["+str(i)+"]!=a["+str(i-1)+"]:\n")
s+=(2*i+2)*tab+"l.append(a.copy())"
exec(s)
return l
I know, there's no need you remember me: exec is ugly, exec can be dangerous, exec isn't easy-readable... I know.
To understand better the function I suggest you to replace exec(s) with print(s).
I give you an example of what string is inside the exec for crp([0,1],2):
for a[0] in iterable:
if 0==0 or a[0]!=a[-1]:
for a[1] in iterable:
if 1==0 or a[1]!=a[0]:
l.append(a.copy())
But, apart from using exec, I need a better functions because crp2 is still too slow (even if faster than crp0); there's any way to recreate the code with r for without using exec? There's any other way to do what I need?
You could prepare the sequences in two halves, then preprocess the second halves to find the compatible choices.
def crp2(I,r):
r0=r//2
r1=r-r0
A=crp0(I,r0) # Prepare first half sequences
B=crp0(I,r1) # Prepare second half sequences
D = {} # Dictionary showing compatible second half sequences for each token
for i in I:
D[i] = [b for b in B if b[0]!=i]
return [a+b for a in A for b in D[a[-1]]]
In a test with iterable=[0,1,2] and r=15, I found this method to be over a hundred times faster than just using crp0.
You could try to return a generator instead of a list. With large values of r, your method will take a very long time to process product(iterable,repeat=r) and will return a huge list.
With this variant, you should get the first element very fast:
from itertools import product
def crp0(iterable, r):
for f in product(iterable, repeat=r):
last = f[0]
b = True
for element in f[1:]:
if element == last:
b = False
break
last = element
if b:
yield f
for no_repetition in crp0([0, 1, 2], 12):
print(no_repetition)
# (0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1)
# (1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0)
Instead of filtering the elements, you could generate a list directly with only the correct elements. This method uses recursion to create the cartesian product:
def product_no_repetition(iterable, r, last_element=None):
if r == 0:
return [[]]
else:
return [p + [x] for x in iterable
for p in product_no_repetition(iterable, r - 1, x)
if x != last_element]
for no_repetition in product_no_repetition([0, 1], 12):
print(no_repetition)
I agree with #EricDuminil's comment that you do not want "Permutations with repetition." You want a significant subset of the product of the iterable with itself multiple times. I don't know what name is best: I'll just call them products.
Here is an approach that builds each product line without building all the products then filtering out the ones you want. My approach is to work primarily with the indices of the iterable rather than the iterable itself--and not all the indices, but ignoring the last one. So instead of working directly with [2, 3, 5, 7] I work with [0, 1, 2]. Then I work with the products of those indices. I can transform a product such as [1, 2, 2] where r=3 by comparing each index with the previous one. If an index is greater than or equal to the previous one I increment the current index by one. This prevents two indices from being equal, and this also gets be back to using all the indices. So [1, 2, 2] is transformed to [1, 2, 3] where the final 2 was changed to a 3. I now use those indices to select the appropriate items from the iterable, so the iterable [2, 3, 5, 7] with r=3 gets the line [3, 5, 7]. The first index is treated differently, since it has no previous index. My code is:
from itertools import product
def crp3(iterable, r):
L = []
for k in range(len(iterable)):
for f in product(range(len(iterable)-1), repeat=r-1):
ndx = k
a = [iterable[ndx]]
for j in range(r-1):
ndx = f[j] if f[j] < ndx else f[j] + 1
a.append(iterable[ndx])
L.append(a)
return L
Using %timeit in my Spyder/IPython configuration on crp3([0,1], 3) shows 8.54 µs per loop while your crp2([0,1], 3) shows 133 µs per loop. That shows a sizeable speed improvement! My routine works best where iterable is short and r is large--your routine finds len ** r lines (where len is the length of the iterable) and filters them while mine finds len * (len-1) ** (r-1) lines without filtering.
By the way, your crp2() does do filtering, as shown by the if lines in your code that is execed. The sole if in my code does not filter a line, it modifies an item in the line. My code does return surprising results if the items in the iterable are not unique: if that is a problem, just change the iterable to a set to remove the duplicates. Note that I replaced your l name with L: I think l is too easy to confuse with 1 or I and should be avoided. My code could easily be changed to a generator: replace L.append(a) with yield a and remove the lines L = [] and return L.
How about:
from itertools import product
result = [ x for x in product(iterable,repeat=r) if all(x[i-1] != x[i] for i in range(1,len(x))) ]
Elaborating on #peter-de-rivaz's idea (divide and conquer). When you divide the sequence to create into two subsequences, those subsequences are the same or very close. If r = 2*k is even, store the result of crp(k) in a list and merge it with itself. If r=2*k+1, store the result of crp(k) in a list and merge it with itself and with L.
def large(L, r):
if r <= 4: # do not end the divide: too slow
return small(L, r)
n = r//2
M = large(L, r//2)
if r%2 == 0:
return [x + y for x in M for y in M if x[-1] != y[0]]
else:
return [x + y + (e,) for x in M for y in M for e in L if x[-1] != y[0] and y[-1] != e]
small is an adaptation from #eric-duminil's answer using the famous for...else loop of Python:
from itertools import product
def small(iterable, r):
for seq in product(iterable, repeat=r):
prev, *tail = seq
for e in tail:
if e == prev:
break
prev = e
else:
yield seq
A small benchmark:
print(timeit.timeit(lambda: crp2( [0, 1, 2], 10), number=1000))
#0.16290732200013736
print(timeit.timeit(lambda: crp2( [0, 1, 2, 3], 15), number=10))
#24.798989593000442
print(timeit.timeit(lambda: large( [0, 1, 2], 10), number=1000))
#0.0071403849997295765
print(timeit.timeit(lambda: large( [0, 1, 2, 3], 15), number=10))
#0.03471425700081454
Please no built-ins besides len() or range(). I'm studying for a final exam.
Here's an example of what I mean.
def find_numbers(x, lst):
lst = [3, 8, 1, 2, 0, 4, 8, 5]
find_numbers(3, lst) # this should return -> (1, 6, 7)
I tried this not fully....couldn't figure out the best way of going about it:
def find_K_highest(lst, k):
newlst = [0] * k
maxvalue = lst[0]
for i in range(len(lst)):
if lst[i] > maxvalue:
maxvalue = lst[i]
newlst[0] = i
Take the first 3 (x) numbers from the list. The minimum value for the maximum are these. In your case: 3, 8, 1. Their index is (0, 1, 2). Build pairs of them ((3,0), (8,1), (1,2)).
Now sort them by size of the maximum value: ((8,1), (3,0), (1,2)).
With this initial List, you can traverse the rest of the list recursively. Compare the smallest value (1, _) with the next element in the list (2, 3). If that is larger (it is), sort it into the list ((8,1), (3,0), (2,3)) and throw away the smallest.
In the beginning you have many changes in the top 3, but later on, they get rare. Of course you have to keep book about the last position (3, 4, 5, ...) too, when traversing.
An insertion sort for the top N elements should be pretty performant.
Here is a similar problem in Scala but without the need to report the indexes.
I dont know is it good to post a solution, but this seems to work:
def find_K_highest(lst, k):
# escape index error
if k>len(lst):
k=len(lst)
# the output array
idxs = [None]*k
to_watch = range(len(lst))
# do it k times
for i in range(k):
# guess that max value is at least at idx '0' of to_watch
to_del=0
idx = to_watch[to_del]
max_val = lst[idx]
# search through the list for bigger value and its index
for jj in range(len(to_watch)):
j=to_watch[jj]
val = lst[j]
# check that its bigger that previously finded max
if val > max_val:
idx = j
max_val = val
to_del=jj
# append it
idxs[i] = idx
del to_watch[to_del]
# return answer
return idxs
PS I tried to explain every line of code.
Can you use list methods? (e.g. append, sort, index?). If so, this should work (I think...)
def find_numbers(n,lst):
ll=lst[:]
ll.sort()
biggest=ll[-n:]
idx=[lst.index(i) for i in biggest] #This has the indices already, but we could have trouble if one of the numbers appeared twice
idx.sort()
#check for duplicates. Duplicates will always be next to each other since we sorted.
for i in range(1,len(idx)):
if(idx[i-1]==idx[i]):
idx[i]=idx[i]+lst[idx[i]+1:].index(lst[idx[i]]) #found a duplicate, chop up the input list and find the new index of that number
idx.sort()
return idx
lst = [3, 8, 1, 2, 0, 4, 8, 5]
print find_numbers(3, lst)
Dude. You have two ways you can go with this.
First way is to be clever. Phyc your teacher out. What she is looking for is recursion. You can write this with NO recursion and NO built in functions or methods:
#!/usr/bin/python
lst = [3, 8, 1, 2, 0, 4, 8, 5]
minval=-2**64
largest=[]
def enum(lst):
for i in range(len(lst)):
yield i,lst[i]
for x in range(3):
m=minval
m_index=None
for i,j in enum(lst):
if j>m:
m=j
m_index=i
if m_index:
largest=largest+[m_index]
lst[m_index]=minval
print largest
This works. It is clever. Take that teacher!!! BUT, you will get a C or lower...
OR -- you can be the teacher's pet. Write it the way she wants. You will need a recursive max of a list. The rest is easy!
def max_of_l(l):
if len(l) <= 1:
if not l:
raise ValueError("Max() arg is an empty sequence")
else:
return l[0]
else:
m = max_of_l(l[1:])
return m if m > l[0] else l[0]
print max_of_l([3, 8, 1, 2, 0, 4, 8, 5])