variation of binary search - python

Say that the target isn't in the list. Instead of outputting -1, I want it to output the rightmost value that's less than the target, followed by the next value (if there is one). In other words, I want to see the gap where the target would be.
If there was a list [1, 2, 4, 7, 7, 8, 9] and I was looking for 5, instead of outputting -1 I want it to output [4, 7]. How do I do that?

Use bisect.bisect to find the insertion point for 5 using binary search, and then take the elements before and after that point:
>>> import bisect
>>> a = [1, 2, 4, 7, 7, 8, 9]
>>> i = bisect.bisect(a, 5)
>>> a[i-1:i+1]
[4, 7]

Related

what does "+3" represents in [:index+3] in python?

Here is the problem statement:
return list[index:]+list[:index+3]
I know [:] represents all the elements of the list.
what does this "+3" represents here?
for this line:
list[:index+3]
if index is set to 1, it is the same as
list[:4]
it's a simple sum on a variable, meaning it will read to 3 positions after your index variable
Every element from [index] till the end plus every element from beginning up to (but not including) [index+3]
Let's have a look at an example:
>>> list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> index=2
>>> list[index:]+list[:index+3]
[3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5]
Here index is 2, thus list[index:]+list[:index+3] is exactly the same as list[index:]+list[0:2+3] which is list[index:]+list[0:5]. So, Every element from [2] till the end plus every element from beginning up to (but not including) [5]

what's the meaning of x[:]=y? [duplicate]

This question already has answers here:
What is the difference between slice assignment that slices the whole list and direct assignment?
(4 answers)
Closed 6 years ago.
I tried to understand [:] in the beginning, but I can't find any document mention it. Where is the best place to learn advanced grammar for Python? Google search won't find [:]. But I figured it out at the end. I just wonder where is best place to learn Python 'tricks'.
For example:
def test(x, y):
x[:] = y
#x = y
>>> a = [0.5,0.6]
>>> b = [0.3]
>>> test(a, b)
>>>
>>> print a
[0.3] # [0.5,0.6]
x[:] means the entire sequence. It's basically x[from:to].
Omitting from means, from the beginning until the to.
>>> numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> numbers[:5]
[0, 1, 2, 3, 4]
Omitting to means, from the from until the end.
>>> numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> numbers[5:]
[5, 6, 7, 8, 9]
Omitting both means the entire list.
>>> numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> numbers[:]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Setting numbers[:] means setting the entire list:
>>> numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> numbers[:] = [1, 2, 3, 4]
>>> numbers
[1, 2, 3, 4]
Keep in mind setting numbers[:] changes that list and does not create a new one. The object will still have the same id().
The term you need to search for is slice. x[start:end:step] is the full form, any one can be omitted to use a default value: start defaults to 0, end defaults to the length of the list, and step defaults to 1. So x[:] means exactly the same as x[0:len(x):1]. You can find more information at
the Expression section of the language reference, and section four of the python tutorial might also be helpful.
The notation x[:] is equivalent to x[0:n] where n is len(x). It specifies the range of elements of x from 0 through n-1 inclusive.
When read, a new list, string, or whatever is created, containing the specified range of elements.
When assigned to, the specified range of elements is destructively replaced in the original. Note that this is allowed for lists, but not for strings.

Smallest number in a particular part of my list

I have a question about python. I have to sort a list of random numbers in a particular way (it's not allowed to use sort()). I'll try to explain:
I have to search for the smallest number, and swap this number with the number at the first position in the list.
Then, I search again for the smallest number, but this time ignore the first number in my list because this one is already sorted. So, I should start searching for the smallest number from the second number (index 1) till the end of the list. The smallest number then found, should be swapped with the second number in the list(so the index 1).
I hope you understand my problem. This is the code I wrote so far, but I get errors and/or the sorting isn't correct.
array = random_integers(10,size=10)
my_list = list(array)
for i in range(len(my_list)):
print my_list
a = min(my_list[i:len(my_list)])
b = my_list.index(a)
my_list[i],my_list[b]=my_list[b],my_list[i]
print my_list
I think there's a problem in my range, and a problem with the
a = min(my_list[i:len(my_list)])
I want to search for the smallest number, but not in the ENTIRE list how can I do this?
The problem occurs on this line:
b = my_list.index(a)
since this searches for the first occurrence of a in all of my_list. If the same number occurs twice, then b will always correspond to the smallest such index, which might be less than i. So you might end up moving a number which has already been sorted.
The obvious thing to try is to slice my_list before calling index:
my_list[i:].index(a)
but note that index will return values between 0 and N-i. We want numbers between i and N. So be sure to add i to the result:
b = my_list[i:].index(a)+i
Thus, the easiest way to fix your code as it presently exists is:
for i in range(len(my_list)):
a = min(my_list[i:])
b = my_list[i:].index(a)+i
my_list[i], my_list[b] = my_list[b], my_list[i]
but notice that min is searching through all the items in my_list[i:] and then the call to index is traversing the same list a second time. You could find b in one traversal like this:
b = min(range(i, N), key=my_list.__getitem__)
Demo:
import numpy as np
array = np.random.random_integers(10,size=10)
my_list = list(array)
N = len(my_list)
for i in range(N):
b = min(range(i, N), key=my_list.__getitem__)
my_list[i], my_list[b] = my_list[b], my_list[i]
print my_list
yields
[3, 10, 9, 6, 5, 3, 6, 8, 8, 4]
[3, 3, 9, 6, 5, 10, 6, 8, 8, 4]
[3, 3, 4, 6, 5, 10, 6, 8, 8, 9]
[3, 3, 4, 5, 6, 10, 6, 8, 8, 9]
[3, 3, 4, 5, 6, 10, 6, 8, 8, 9]
[3, 3, 4, 5, 6, 6, 10, 8, 8, 9]
[3, 3, 4, 5, 6, 6, 8, 10, 8, 9]
[3, 3, 4, 5, 6, 6, 8, 8, 10, 9]
[3, 3, 4, 5, 6, 6, 8, 8, 9, 10]
[3, 3, 4, 5, 6, 6, 8, 8, 9, 10]
If you want the smallest number from a list you can use min(). If you want a part of a list you can use list slicing: my_list[1:]. Put the two together and you get the smallest number from a part of your list. However, you don't need to do this, as you can .pop() from the list instead.
sorted_list = []
while my_list:
n = min(my_list)
sorted_list.append(my_list.pop(my_list.index(n)))
If you're using numpy arrays then instead of my_list.index(min(my_list)) you can use the .argmin() method.
While this type of sorting is good for an introduction, it is not very efficient. You may want to consider looking at the merge sort, and also the Python's built-in timsort.

swapping one number with two numbers in a list in python

If I am given a list of numbers and I want to swap one of them with the next two numbers.
Is there a way to do this in one shot, without swapping the first number twice?
To be more specific, let's say I have the following swap function:
def swap_number(list, index):
'''Swap a number at the given index with the number that follows it.
Precondition: the position of the number being asked to swap cannot be the last
or the second last'''
if index != ((len(list) - 2) and (len(list) - 1)):
temp = list[index]
list[index] = list[index+1]
list[index+1] = temp
Now, how do I use this function to swap a number with the next two numbers, without calling swap on the number twice.
For example: I have the following list: list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Now, how do I swap 3 with the 4 and 5 in one shot?
The expected output would be
list = [0, 1, 2, 4, 5, 3, 6, 7, 8, 9]
Something like this?
def swap(lis, ind):
lis.insert(ind+2, lis.pop(ind)) #in-place operation, returns `None`
return lis
>>> lis = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> lis = swap(lis, 3)
>>> lis
[0, 1, 2, 4, 5, 3, 6, 7, 8, 9]

loop until all elements have been accessed N times in python

I have a group of buckets, each with a certain number of items in them. I want to make combinations with one item from each bucket. The loop should keep making different combinations until each item has participated in at least some defined number.
I can easily see how to run the loop and stop once a single element has been accessed a certain number of times. However I can't see how to set a minimum cutoff point beyond searching through all the elements in all the buckets to check their access number after every iteration of the loop.
itertools.product is one way (a very systematic one) to make the "combinations" you request (don't confuse with the .combinations function of course) -- or you could make them randomly with random.choose from each bucket; not sure which one is for you since I don't know what your real purpose is.
Anyway, I'd keep track of how many combos each item has been in with a dict (or one dict per bucket, if there can be overlap in items among buckets). Or, you could use a collections.Counter in Python 2.7, if that's your version.
At any rate, one possibility to do what you request is: the moment an item's count reaches N, remove that item from its bucket (or all buckets, if there's overlap and that's the semantics you require) -- except that if this leaves the bucket empty, restore the bucket's contents and mark that bucked as "done" (you don't need to remove items from a done bucket) e.g. by adding the bucket's index to a set.
You're done when all buckets are done (whether it be randomly or systematically).
Need some code to explain this better? Then please specify the overlap semantics (if overlap is possible) and the systematic-or-random requirements you have.
try
visits = defaultdict(int)
# do at each node visiting
visits[n] += 1
if visits[n] >= MAX_VISITS:
break
print 'done'
Use a dictionary with the items as keys. Every time the item is used, update its count. Then check to see whether all the values are at least above the threshold, ie:
counter = dict()
while min(counter.values) < threshold:
# make a combination
# and update the dictionary
In vanilla Python, this seems to do the job:
buckets = [ [1,2,3],[4],[5,6],[7,8,9,0] ]
def combo(b, i = 0, pref = []):
if len(b) > i:
c = b[i]
for v in c:
combo(b, i + 1, pref + [v])
else:
print pref
combo(buckets)
Output:
[1, 4, 5, 7]
[1, 4, 5, 8]
[1, 4, 5, 9]
[1, 4, 5, 0]
[1, 4, 6, 7]
[1, 4, 6, 8]
[1, 4, 6, 9]
[1, 4, 6, 0]
[2, 4, 5, 7]
[2, 4, 5, 8]
[2, 4, 5, 9]
[2, 4, 5, 0]
[2, 4, 6, 7]
[2, 4, 6, 8]
[2, 4, 6, 9]
[2, 4, 6, 0]
[3, 4, 5, 7]
[3, 4, 5, 8]
[3, 4, 5, 9]
[3, 4, 5, 0]
[3, 4, 6, 7]
[3, 4, 6, 8]
[3, 4, 6, 9]
[3, 4, 6, 0]
There is no doubt a more Pythonic way of doing it.

Categories

Resources