python bisect.insort(list, value) - python

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.

Related

If heapq.heapify(list) is O(N) and list.sort() is O(NlogN) then why isn't the default sort algorithm heapify?

If I have a list and need to sort it, is there a good reason to use list.sort() over heapq.heapify(list), given that heapify is O(N) (link) and .sort() is O(NlogN)?
Why isn't the default sort algorithm heapify if heapify is faster?
as guys have said in the comment section, "heapify" rearranges elements of the list to form a heap-oriented binary tree. complete binary trees can be represented using arrays or in other words, any array which is fully filled with comparable values can be logically viewed as a complete binary tree.
by definition from wikipedia, complete binary tree is:
A complete binary tree is a binary tree in which every level, except
possibly the last, is completely filled, and all nodes in the last
level are as far left as possible.
see an example:
a = [5, 3, 8, 2, 4, 6, 10] ---> heapq.heapify(a)
to form a heap you need to satisfy 2 rules:
form a complete binary tree
sort the tree so that the children of each node are greater than or equal to the parent node for each node in the tree.
that's exactly what heapify does, it rearranges elements in the array to satisfy those 2 conditions.
as you can see in the picture above, just by taking the top element (root) each time, you'll access tree elements in a sorted fashion or in other words you can use heaps to sort your array in n*logn time:
import heapq
a = [5, 3, 8, 2, 4, 6, 10]
def sort_with_heap(a):
"""
sort O(nlogn)
"""
heapq.heapify(a) # heapify's the list O(n)
while len(a) > 0: # O(n) times
yield heapq.heappop(a) # O(logn)
print(list(sort_with_heap(a)))
>> [2, 3, 4, 5, 6, 8, 10]
note: that the example above is for the sake of understanding how heaps can be used for sorting and is not space optimal. to do proper sorting using heaps take a look at heapsort (which works with max-oriented heaps) and doesn't use any additional space than the sorting array itself. i've wrote one myself in here.

Why list(map(func, set)) always gives a sorted list in Python?

While learning about map(function, *iterables) function, I found that it applies the function with n number of arguments where n is the number of supplied iterables as args to the map() function. So, I tried and it's working as expected.
Another point is lists in Python maintain the insertion order while sets are unordered. Apart from having all these details, I'm unable to understand that -
Why does applying map() on a set and then converting the resultant map object to a list give me a sorted list while applying map() on a list and then converting the map object to a list gives me a list with the same order as it was in the supplied list?
This is my source code:
l1 = [1, 2, 4, 5, 3]
s1 = {6, 7, 9, 8, 0}
print(list(map(lambda num: num * 2, l1)))
print(list(map(lambda num: num * 2, s1)))
and this is the output:
[2, 4, 8, 10, 6]
[0, 12, 14, 16, 18]
In case of:
print(list(map(lambda num: num * 2, s1)))
each time I run the program, I'm getting the same sorted list but if I print(s1) I'm getting different orders of s1. Shouldn't I get a list with random order of doubled numbers each time I run the program?
P.S.
Another user, suggested me a possible duplicate order-of-unordered-python-sets. But, if possible, I seek an updated answer for this question that talks about the implementation of sets in current versions of Python (as of now the current version is 3.10.7).
The order-of-unordered-python-sets definitely gives a base to under the reason behind this problem. But please provide your updated answers here so that it'll be relevant for upcoming years. Otherwise, you can definitely vote to close it.
You picked a very bad sample since {6, 7, 9, 8, 0} is printed as {0, 6, 7, 8, 9} which appears to be sorted, but it is not, it just happens to be the same order as something that is sorted. Pick {16, 6, 7, 9, 8, 0} instead and you will see {0, 16, 6, 7, 8, 9} in the output, obviously not sorted or ordered.
(Unordered) sets do have an order that you MUST NOT rely on, even / especially if you think you found order in it. Any order you see is purely by chance.
sets are unordered (not randomly ordered), in your case, it was just a coincidence that your specific series of elements were printed in order. If you run the same code but with different set elements, they may end up being out of order.

I want to implement bubblesort using python list comprehension but it displays blank

I want to implement bubblesort using python list comprehension but it displays blank. Tried using assignment operators to swap (l[j]=l[j+1]) but it throws an error as list comprehension does not support assignment
l = [8, 1, 3, 5, 4, 6, 7, 2]
newlist= [ [(l[j],l[j+1]),(l[j+1],l[j])] for i in range(1,len(l)-1) for j in range(0,len(l)-1) if l[j]>l[j+1] ]
Expected output is: 1, 2, 3, 4, 5, 6, 7, 8
But I am getting the output as [].
This fails from a conceptual problem, which is that every filtered result must produce a value to include in the list. Your list comprehension has no capability to store intermediate results -- it's doomed to failure. You have to determine whether to emit a value, and which value to emit, given only the original list, i, and j. That information does not exist with bubble-sort logic.
For instance, consider the first nested iteration. You have this information at hand:
l = [8,1,3,5,4,6,7,2]
i = 1
j = 0
Given this, you must decide right now whether or not to put information into y our final list -- if so, which information to put there. You cannot defer this to a second pass, because you have no temporary storage within the comprehension.
See the problem?

Where am I wrong?

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.

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.

Categories

Resources