1

Having:

class Foo:
   def __init__(self, a, b):
       self.a = a 
       self.b = b

and a list like:

l = [Foo(1, 2), Foo(1, 3), Foo(1, 4), Foo(1, 10)]

If I want to count the number of objects having a == 1, I do

>>> count_a = len([o for o in l if o.a == 1]) 
>>> assert count_a == 4 

It is not a function in the library to allow me to execute somthing like:

>>> from operator import attrgetter
>>> count(l, key=attrgetter('a'))
4 
mozway
  • 194,879
  • 13
  • 39
  • 75
  • 1
    This is basically the same as [this question](https://stackoverflow.com/questions/7549525/use-lambda-expression-to-count-the-elements-that-im-interested-in-python) looks like Python needs to borrow [`std::count_if`](https://en.cppreference.com/w/cpp/algorithm/count) from C++ – Cory Kramer Oct 15 '21 at 14:22
  • You probably want to change the signature of `count` to allow for a numeric value to compare the field value against it. – Dima Chubarov Oct 15 '21 at 14:22
  • You could also use `getattr(obj, attr)` if your attribute name is variable – Cyrille Pontvieux Oct 15 '21 at 14:25
  • I think you are missing an argument in your desired function, how it is going to know that o.a == 1 – Dani Mesejo Oct 15 '21 at 14:29
  • I think it is a stupid question. Sorry to waste your time. –  Oct 15 '21 at 14:33
  • Why do you say that? It is a good, well written question. It just happens to been asked already... – Tomerikoo Oct 15 '21 at 14:35
  • I thought that may be should be a faster way to count than the list comprehension or sum and generator, hiding details in the library or something like that .. It is not that I was asking how to write a hypothetic function. I mean I was trying to leverage and not reinvent the wheel. –  Oct 15 '21 at 14:38

1 Answers1

2

You can use sum and a generator:

sum(1 for o in l if o.a==1)

output: 4

NB. sum(o.a == 1 for o in l) would also work but this is twice slower, presumably as all items reach and are computed by sum

mozway
  • 194,879
  • 13
  • 39
  • 75
  • That is basically the same, in spirit, to their list comprehension and I do not feel addresses their primary question which I interpret as "is there a library function to count from a container using a lambda to specify a predicate" – Cory Kramer Oct 15 '21 at 14:24
  • This is not a comprehension, this is a sequence generator. – Cyrille Pontvieux Oct 15 '21 at 14:25
  • 1
    It can also be written more succinctly as `sum(o.a == 1 for o in l)` – Tomerikoo Oct 15 '21 at 14:26
  • @Cory I feel it is quite different in the sense that you don't have to build and store a list of potentially big objects. Here there is just a generator. – mozway Oct 15 '21 at 14:26
  • @DmitriChubarov yes but I'm not sure it would be faster, I don't know the code of sum, but if this passes 0/False to sum then there are unnecessary operations – mozway Oct 15 '21 at 14:27
  • @Tomerikoo I just compared `sum(condition for object in list)` and `sum(1 for object in list if condition)` and the second is ~2 times faster, so the slightly shorter code is not worth it ;) – mozway Oct 15 '21 at 14:31
  • That's a very interesting conclusion. Thank you. It makes sense thinking about it: the boolean need to be converted to int and summed, while in your approach the condition is only checked and 1is always added – Tomerikoo Oct 15 '21 at 14:33