简体   繁体   中英

Python counter values and boolean all() not working as expected

This has really got me stumped. I have a bunch of Counters, and I want to check if all of the values meet a certain condition. Using all() makes sense. So I set it up like so:

>>> from collections import Counter
>>> my_counter = Counter(['a', 'b', 'a', 'c', 'a', 'b', 'c'])
>>> my_counter
Counter({'a': 3, 'b': 2, 'c': 2})

all() works on iterables, Counter.values() returns an iterable, the individual values are integers, and yet:

>>> all(my_counter.values())>1
False

What am I missing here?

Try and check this code. The last line does what you intend to do. all(my_counter.values()) tells us if all the values within the counter are iterable. Check https://www.programiz.com/python-programming/methods/built-in/all

#python 3.5.2
from collections import Counter
my_counter = Counter(['a', 'b', 'a', 'c', 'a', 'b', 'c'])
for row in ((my_counter.values())):
    print(row)
print(all(i > 1 for i in my_counter.values()))

all essentially just does:

def all(iterable):
    for item in iterable:
        if not item:
            return False
    return True

That means it will just check if all values are "truthy", in your case all values are != 0 so they are considered True and so:

>>> all(my_counter.values())
True

But True (which behaves like the integer 1 ) is not > 1 so the result will be False :

>>> all(my_counter.values()) > 1
False

What you want is to check if every value is greater than one, then you could either just use a self-written variant of all :

def all_greater_than_one(iterable):
    for item in iterable:
        if item <= 1:
            return False
    return True

>>> all_greater_than_one(my_counter.values())
True

Or use a generator expression to "transform" the iterable passed to all :

>>> all(value > 1 for value in my_counter.values())
True

Note that you could also use a list-comprehension here instead of the generator expression:

>>> all([value > 1 for value in my_counter.values()])
True

Or some other way to transform it - I'm not recommending the following because the generator or comprehension is generally better, just to show some alternatives:

>>> all(map(lambda x: x > 1, my_counter.values()))
True
>>> all(map((1).__le__, my_counter.values()))  # avoid this, just here for entertainment.
True

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