Using bisect in the tuple list, but compare using only the first value

I read this question about how to use bisecttuples in a list, and I used this information to answer this question . It works, but I would like to get a more general solution.

Since it bisectdoesn’t allow you to specify a function key, if I have this:

import bisect
test_array = [(1,2),(3,4),(5,6),(5,7000),(7,8),(9,10)]

and I want to find the first element where x > 5for these (x,y)tuples (without considering at all y, I am doing this now:

bisect.bisect_left(test_array,(5,10000))

and I get the correct result because I know that no is ygreater than 10000, so it bisectpoints me to an index (7,8). If I put it 1000, it would be wrong.

For integers, I could do

bisect.bisect_left(test_array,(5+1,))

, , , 2- ?

test_array = [(1,2),(3,4),(5.2,6),(5.2,7000),(5.3,8),(9,10)]

:

bisect.bisect_left(test_array,(min_value+sys.float_info.epsilon,))

, :

bisect.bisect_left(test_array,(min_value+sys.float_info.epsilon*3,))

. . - ?

+4
4

bisect . bisect , bisect :

class KeyList(object):
    # bisect doesn't accept a key function, so we build the key into our sequence.
    def __init__(self, l, key):
        self.l = l
        self.key = key
    def __len__(self):
        return len(self.l)
    def __getitem__(self, index):
        return self.key(self.l[index])

bisect KeyList O (log n) bisect :

bisect.bisect_right(KeyList(test_array, key=lambda x: x[0]), 5)
+1

(quick'n'dirty) bisect_left, :

def bisect(lst, value, key=None):
    if key is None:
        key = lambda x: x
    def bis(lo, hi=len(lst)):
        while lo < hi:
            mid = (lo + hi) // 2
            if key(lst[mid]) < value:
                lo = mid + 1
            else:
                hi = mid
        return lo
    return bis(0)

> from _operator import itemgetter
> test_array = [(1, 2), (3, 4), (4, 3), (5.2, 6), (5.2, 7000), (5.3, 8), (9, 10)]
> print(bisect(test_array, 5, key=itemgetter(0)))
3

O(log_N), list. , bisect_left . , .

+3

:

... , x > 5 (x, y) ( y )

- :

import bisect
test_array = [(1,2),(3,4),(5,6),(5,7000),(7,8),(9,10)]

first_elem = [elem[0] for elem in test_array]
print(bisect.bisect_right(first_elem, 5))

bisect_right , , , .... , .

-, , bisect .

, , - itertools (, ):

import itertools
test_array = [(1,2),(3,4),(5,6),(5,7000),(7,8),(9,10)]

print(itertools.ifilter(
    lambda tp: tp[1][0]>5, 
    ((ix, num) for ix, num in enumerate(test_array))).next()[0]
)
+2

, , float ( )

bisect.bisect_left(test_array,(min_value+abs(min_value)*sys.float_info.epsilon),))

( min_value ). epsilon, min_value, min_value ( /). , min_value bisect.

, :

bisect.bisect_left(test_array,(min_value+1,))
+2

Source: https://habr.com/ru/post/1669308/


All Articles