简体   繁体   中英

Fastest way to get minimum elements in a list less than a particular element

I am better off explaining with an example
Suppose, I have a list [6,3,5,1,4,2].

Starting from index 0, find all items that are smaller (that have not been marked) than the value at that index.

Index 0: [6,3,5,1,4,2]  
Elements less than 6: 5{3,5,1,4,2} 
Visited array: [1 0 0 0 0 0]

Index 1: [6,3,5,1,4,2]  
Elements less than 3: 2 {1,2}
Visited array: [1 1 0 0 0 0]

Index 2: [6,3,5,1,4,2]  
Elements less than 5: 3 {1,4,2}
Visited array: [1 1 1 0 0 0]

Index 3: [6,3,5,1,4,2]  
Elements less than 1: 0 {NULL}
Visited array: [1 1 1 1 0 0]

Index 4: [6,3,5,1,4,2]  
Elements less than 4: 1 {2}
Visited array: [1 1 1 1 1 0]

This yields an array as [5 2 3 0 1 0]

Currently using,

def get_diff(lis):
    ans=[]
    for index,elem in enumerate(lis):
        number_of_smaller=len(filter(lambda x:x<elem ,lis[index+1:]))
        ans.append(number_of_smaller)
    return ans

However, I have a feeling that this will not be efficient. How do I make it worthy of a huge list? Do I smell prefix sums?. Thanks,

You can simply use a list comprehension within a dict comprehension to preserve the item as the key and the items which are less than it as the value (and use collections.OrderedDict to preserve the order):

>>> from collections import OrderedDict
>>> def get_diff(lis):
...        return OrderedDict((item,[i for i in lis if i<item]) for item in lis)

Since your condition is < there is no need to exclude the item itself, because that the cost of removing it in comparison is greater than including it.

Also if you want to preserve the indices to you can use enumerate to loop over your list :

def get_diff(lis):
       return OrderedDict((item,index),[i for i in lis if i<item]) for index,item in enumerate(lis))

And if you want to count the number of that items you can use a generator expression within sum function :

>>> from collections import OrderedDict
>>> def get_diff(lis):
...        return OrderedDict((item,sum(1 for i in lis if i<item)) for item in lis)

NOTE: if you want to count the item less than any item after that (with larger index) you can simply use a indexing in your loop :

>>> def get_diff(lis):
...        return OrderedDict((item,sum(1 for i in lis[index:] if i<item)) for index,item in enumerate(lis))
... 
>>> get_diff(l).values()
[5, 2, 3, 0, 1, 0]
my_list = [6,3,5,1,4,2] 

def get_diff(lis):
    result = []
    for visited, i in enumerate(range(len(lis))):
        limit = lis[i]
        elem = filter(None, [x if x < limit else None for x in lis][visited + 1:])
        result.append(len(elem))
    return result

print get_diff(my_list)
#[5, 2, 3, 0, 1, 0]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM