Search code examples
pythonloopsfor-in-loop

Python all()/any() like method for a portion/part of list?


What would be the most elegant/pythonic way of achieving: "if x% of total values in a list are greater than the y, return true". I have currently implemented a function:

def check(listItems, val):
   '''A method to check all elements of a list against a given value.
   Returns true if all items of list are greater than value.'''
   return all(x>val for x in listItems)

But for my use case, waiting for this particular condition is quite costly and somewhat useless. I would want to proceed if ~80% of the items in list are greater than the given value. One approach in my mind is to sort the list in descending order, create another list and copy 80% of the elements of list to the new list, and run the function for that new list. However, I am hoping that there must be a more elegant way of doing this. Any suggestions?


Solution

  • It sounds like you are dealing with long lists which is why this is costly. If would be nice if you could exit early as soon as a condition is met. any() will do this, but you'll want to avoid reading the whole list before passing it to any(). One options might be to use itertools.accumulate to keep a running total of True values and the pass that to any. Something like:

    from itertools import accumulate
    
    a = [1, 2, 2, 3, 4, 2, 4, 1, 1, 1]
    
    # true if 50% are greater than 1
    goal = .5 * len(a) # at least 5 out of 10   
    any( x > goal for x in accumulate(n > 1 for n in a))
    

    accumulate won't need to read the whole list — it will just start passing the number of True values seen up to that point. any should short-circuit as soon as it finds a true value, which in the above case is at index 5.