Where am I wrong? - python

Question
Write function mssl() (minimum sum sub-list) that takes as input a list of integers.It then computes and returns the sum of the maximum sum sub-list of the input list. The maximum sum sub-list is a sub-list (slice) of the input list whose sum of entries is largest. The empty sub-list is defined to have sum 0. For example, the maximum sum sub-list of the list [4, -2, -8, 5, -2, 7, 7, 2, -6, 5] is [5, -2, 7, 7, 2] and the sum of its entries is 19.
l = [4, -2, -8, 5, -2, 7, 7, 2, -6, 5]
mssl(l)
19
mssl([3,4,5])
12
mssl([-2,-3,-5])
0
In the last example, the maximum sum sub-list is the empty sub-list because all list items are
negative.
THIS IS MY SOLUTION
def mssl(lst):
pos,neg,TotalList=[],[],[]
for items in range(len(lst)):
if(lst[items]>0):
pos+=[lst[items]]
else:
neg+=[lst[items]]
TotalPos=sum(pos)
TotalNeg=sum(neg)
if(len(neg)>0):
for negatives in range(len(neg)):
TotalList=[TotalPos+neg[negatives]]
if(TotalList>TotalList[negatives-1]):
print(TotalList)
else:
TotalList=TotalPos
print(TotalList)
THIS IS NOT A HOMEWORK QUESTION I AM LEARNING PYTHON FOR FUN, PLEASE LET ME KNOW WHERE I AM WRONG

It looks like you're trying to learn programming, with python as your first language. This particular problem is a somewhat difficult one to start with. I would advise you to take a straightforward, brute-force approach at first. Evaluate the sums of all the subsequences, one after another, and keep track of which is largest. Once you have a function that will produce the correct answer, you can look for a better (faster, more elegant, whatever) solution.
As to your code, it really has nothing to do with the question. For example, TotalList is always a one-element list. The expression TotalList[negatives-1] doesn't make much sense; if there's only one element in the list, you can access it as TotalList[0]. The expression TotalList>TotalList[negatives-1] makes no sense at all; you don't want to compare a list to a number.
This is a well-known problem, and a simple, fast solution is not at all easy to come up with, so don't be discouraged if you don't find it. Once you get a straightforward solution, you can think about an elegant one. This problem can be solved in one line of python, using list comprehensions. Trying to do that will lead to improvement in your python style. For example, instead of writing
for items in range(len(lst)):
if(lst[items]>0):
pos+=[lst[items]]
else:
neg+=[lst[items]]
you can, and should write
pos = [x for x in lst if x > 0]
neg = [x for x in lst if x < 0]
Good luck learning python.

Related

why does my quick sort sometimes miss a pair of numbers?

ive made my own quick sort algorithm and it works fairly well, expect every 3 or 4 sorts, it misses a pair of numbers and the final list remains to be unsorted.
for example, instead of the list being [1, 2, 3, 4, 5, 6], it'll be [1, 2, 3, 5, 4, 6]
this is my code
for i in range(len(lista)):
pivot = random.choice(lista)
for j in range(len(lista)):
if lista[j]>pivot and lista.index(lista[j])<lista.index(pivot):
lista[lista.index(pivot)] = lista[j]
lista[j] = pivot
elif lista[j]<pivot and lista.index(lista[j])>lista.index(pivot):
lista[lista.index(pivot)] = lista[j]
lista[j] = pivot
else:
j = j
i dont know what the issue might be, even visualizing the code in python tutor doesnt help because in the first pivot selection, it always picks the same pivots
help
As far as I know the quick sort algorithm requires you to use recursion, to apply the algorithm in each sublist created once you choose a pivot.
In the example that you have you are choosing a pivot randomly for each item of the list, it could sort the list if at the end you have chosen all items at least once (or maybe the majority of them, I am not sure), but since you are choosing them randomly it is probably that sometimes the pivots chosen are not enough to order the list properly.

python bisect.insort(list, value)

does this python module computes an ordered insert into a data structure or it inserts and then sort? been struggling with this kind of thing in python since developing an algorithm in which I have to keep in mind memmory issues thus need a way to insert into a list just in the right position, as it should be done in java using a linkedlist but not sure what to use and how.
Any help will be much appreciated.
This insert value in a list at the correct position, note that it assumes is already sorted. From the documentation:
Insert x in a in sorted order. This is equivalent to
a.insert(bisect.bisect_left(a, x, lo, hi), x) assuming that a is
already sorted. Keep in mind that the O(log n) search is dominated by
the slow O(n) insertion step.
The last part refers to the fact that insertion on a Python list is O(n). The search is done using binary search.
If you start from an empty list and repeatedly use this algorithm to insert the objects into a list, the final list will be sorted. This algorithm is known as binary insertion sort. For example:
import bisect
l = [1, 3, 7, 5, 6, 4, 9, 8, 2]
result = []
for e in l:
bisect.insort(result, e)
print(result)
Output
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Note: The complexity of this algorithm is O(n*n) given the O(n) insertion step.

Swapping maximum and minimum values in a list

Given a list (for instance, [1,1,2,1,2,2,3]) which is not sorted highest to lowest, and contains multiples of all numbers, I need to swap, in place, the maximums with the minimums, the second maxes with the second mins, etc. So, our example list would become [3,3,2,3,2,2,1].
Also, just to clarify, it's not just the max and min, but each layer of maxes and mins. So if the max was 4, 1's and 4's should switch as well as 2's and 3's.
I found this question on the topic: How to swap maximums with the minimums? (python)
but the code examples given seemed verbose, and assumed that there were no duplicates in the list. Is there really no better way to do this? It seems like a simple enough thing.
This is one way to do it, possible because Python is such an expressive language:
>>> a = [1,1,2,1,2,2,3]
>>> d = dict(zip(sorted(set(a)), sorted(set(a), reverse=True)))
>>> [d[x] for x in a]
[3, 3, 2, 3, 2, 2, 1]

Optimized method of cutting/slicing sorted lists

Is there any pre-made optimized tool/library in Python to cut/slice lists for values "less than" something?
Here's the issue: Let's say I have a list like:
a=[1,3,5,7,9]
and I want to delete all the numbers which are <= 6, so the resulting list would be
[7,9]
6 is not in the list, so I can't use the built-in index(6) method of the list. I can do things like:
#!/usr/bin/env python
a = [1, 3, 5, 7, 9]
cut=6
for i in range(len(a)-1, -2, -1):
if a[i] <= cut:
break
b = a[i+1:]
print "Cut list: %s" % b
which would be fairly quick method if the index to cut from is close to the end of the list, but which will be inefficient if the item is close to the beginning of the list (let's say, I want to delete all the items which are >2, there will be a lot of iterations).
I can also implement my own find method using binary search or such, but I was wondering if there's a more... wide-scope built in library to handle this type of things that I could reuse in other cases (for instance, if I need to delete all the number which are >=6).
Thank you in advance.
You can use the bisect module to perform a sorted search:
>>> import bisect
>>> a[bisect.bisect_left(a, 6):]
[7, 9]
bisect.bisect_left is what you are looking for, I guess.
If you just want to filter the list for all elements that fulfil a certain criterion, then the most straightforward way is to use the built-in filter function.
Here is an example:
a_list = [10,2,3,8,1,9]
# filter all elements smaller than 6:
filtered_list = filter(lambda x: x<6, a_list)
the filtered_list will contain:
[2, 3, 1]
Note: This method does not rely on the ordering of the list, so for very large lists it might be that a method optimised for ordered searching (as bisect) performs better in terms of speed.
Bisect left and right helper function
#!/usr/bin/env python3
import bisect
def get_slice(list_, left, right):
return list_[
bisect.bisect_left(list_, left):
bisect.bisect_left(list_, right)
]
assert get_slice([0, 1, 1, 3, 4, 4, 5, 6], 1, 5) == [1, 1, 3, 4, 4]
Tested in Ubuntu 16.04, Python 3.5.2.
Adding to Jon's answer, if you need to actually delete the elements less than 6 and want to keep the same reference to the list, rather than returning a new one.
del a[:bisect.bisect_right(a,6)]
You should note as well that bisect will only work on a sorted list.

average of the list in Python

I have a problem: i need to find an average of the list using this scheme:
First of all, we find an average of two elements, three elements..... len(list) elements and form a new list using averages. The use .pop() and find all averages again. Function should stop when len(list) == 2. Recursion should be used.
Example:
list: [-1, 4, 8, 1]
1 step:
find an average of [-1, 4], [-1, 4, 8], [-1, 4, 8, 1]
Then we form a new list: [1.5, 3.66..., 3] (averages)
Then find averages of new list: [1.5, 3.66...], [1.5, 3.66..., 3]
Then we form a new list: [2.5833.., 7.222...] (averages)
When len(list) == 2, find an average of this two elements.
Answer is 2.652777.
What should i write:
jada = []
while True:
print 'Lst elements:'
a = input()
if (a == ''):
break
jada.append(a)
print 'Lst is:' + str(Jada)
def keskmine(Jada):
for i in range(len(Jada) - 1):
...
jada.pop()
return keskmine(Jada)
Actually, this is a part of a homework, but i don't know how to solve it.
Accept the list as the function argument. If the list has one item, return that. Create two iterators from the list. Pop one item off one of the lists, zip them together, then find the averages of the zip results. Recurse.
In short, you're finding the "running average" from a list of numbers.
Using recursion would be helpful here. Return the only element when "len(lst) == 1" otherwise, compute the running average and recurse.
There are two parts in this assignment. First, you need to transform lists like [-1, 4, 8, 1] to lists like [1.5, 3.66, 3] (find the running averages). Second, you need to repeat this process with the result of the running averages until your list's length is 2 (or 1).
You can tackle the first problem (find the running averages) independently from the second. Finding the running average is simple, you first keep track of the running sum (e.g. if the list is [-1, 4, 8, 1] the running sum is [-1, 3, 11, 12]) and divide each elements by their respective running index (i.e. just [1, 2, 3, 4]), to get [-1/1, 3/2, 11/3, 12/4] = [-1, 1.5, 3.66, 3]. Then you can discard the first element to get [1.5, 3.66, 3].
The second problem can be easily solved using recursion. Recursion is just another form of looping, all recursive code can be transformed to a regular for/while-loops code and all looping code can be transformed to recursive code. However, some problems have a tendency towards a more "natural" solution in either recursion or looping. In my opinion, the second problem (repeating the process of taking running averages) is more naturally solved using recursion. Let's assume you have solved the first problem (of finding the running average) and we have a function runavg(lst) to solve the first problem. We want to write a function which repeatedly find the running average of lst, or return the average when the lst's length is 2.
First I'll give you an explanation, and then some pseudo code, which you'll have to rewrite in Python. The main idea is to have one function that calls itself passing a lesser problem with each iteration. In this case you would like to decrease the number of items by 1.
You can either make a new list with every call, or reuse the same one if you'd like. Before passing on the list to the next iteration, you will need to calculate the averages thus creating a shorter list.
The idea is that you sum the numbers in a parameter and divide by the number of items you've added so far into the appropriate index in the list. Once you are done, you can pop the last item out.
The code should look something like this: (indexes in sample are zero based)
average(list[])
if(list.length == 0) // Check input and handle errors
exit
if(list.length == 1) // Recursion should stop
return list[0] // The one item is it's own average!
// calculate the averages into the list in indices 0 to length - 2
list.pop() // remove the last value
return average(list) // the recursion happens here
This is also an opportunity to use python 3.x itertools.accumulate:
From docs:
>>> list(accumulate(8, 2, 50))
[8, 10, 60]
Then, you only need to divide each item by its index increased by 1, eliminate the first element and repeat until finished
For example, this works for any list of any length, doing most of the above-indicated steps inside a list comprehension:
>>> from itertools import accumulate
>>> a = [-1, 4, 8, 1]
>>> while len(a) > 1:
a = [item / (index + 1) for (index, item) in enumerate(accumulate(a)) if index > 0]
>>> print(a)
[2.6527777777777777]

Categories

Resources