# counting items

Discussion in 'Python' started by It's me, Jan 12, 2005.

1. ### It's meGuest

Okay, I give up.

What's the best way to count number of items in a list?

For instance,

a=[[1,2,4],4,5,[2,3]]

I want to know how many items are there in a (answer should be 7 - I don't
want it to be 4)

I tried:

b=len([x for y in a for x in y])

That doesn't work because you would get an iteration over non-sequence.

I tried:

g=lambda x: (1,len(x))[isinstance(x,(list,tuple,dict))]
b=sum(lambda(x) for x in a)

and that didn't work because I get a TypeError from the len function (don't
know why)

I can, of course:

i=0
for x in a:
if isinstance(x,(list,tuple,dict)):
i += len(x)
else:
i += 1

but that's so C-like...

Thanks,

It's me, Jan 12, 2005

2. ### Andrew KoenigGuest

"It's me" <> wrote in message
news:ukdFd.10645\$...

> What's the best way to count number of items in a list?
>
> For instance,
>
> a=[[1,2,4],4,5,[2,3]]
>
> I want to know how many items are there in a (answer should be 7 - I don't
> want it to be 4)

def totallen(x):
if isinstance(x, (list, tuple, dict)):
return sum(map(totallen, x))
return 1

Andrew Koenig, Jan 12, 2005

3. ### Paul McGuireGuest

"It's me" <> wrote in message
news:ukdFd.10645\$...
> Okay, I give up.
>
> What's the best way to count number of items in a list?
>
> For instance,
>
> a=[[1,2,4],4,5,[2,3]]
>
> I want to know how many items are there in a (answer should be 7 - I don't
> want it to be 4)
>

<snip>

I've sure seen a lot of questions about the flattening of lists. I found
this version of flatten somewhere, I thought I got it from the Python
Cookbook but I can't find it now. Perhaps it was posted here on c.l.py. I
*don't* claim authorship, I'm merely an admirer of such a clean-looking
solution.

def flatten(a):
if not isinstance(a, (tuple,list)): return [a]
if len(a)==0: return []
return flatten(a[0])+flatten(a[1:])

a = [[1, 2, 4], 4, 5, [2, 3], 6, [6], [], 'askjdf']

print len(flatten(a))

gives the value 10.

Considering how often this comes up, might there be a place for some sort of
flatten() routine in the std dist, perhaps itertools?

-- Paul

Paul McGuire, Jan 12, 2005
4. ### Mark McEahernGuest

It's me wrote:

>Okay, I give up.
>
>What's the best way to count number of items in a list [that may contain lists]?
>
>

a = [[1,2,4],4,5,[2,3]]

def iterall(seq):
for item in seq:
try:
for subitem in iterall(item):
yield subitem
except TypeError:
yield item

all = [x for x in iterall(a)]
print len(all)

Mark McEahern, Jan 12, 2005
5. ### It's meGuest

Thanks.

May be flatten should be build into the language somehow....

"Paul McGuire" <._bogus_.com> wrote in message
news:aKdFd.8991\$...
> "It's me" <> wrote in message
> news:ukdFd.10645\$...
> > Okay, I give up.
> >
> > What's the best way to count number of items in a list?
> >
> > For instance,
> >
> > a=[[1,2,4],4,5,[2,3]]
> >
> > I want to know how many items are there in a (answer should be 7 - I

don't
> > want it to be 4)
> >

> <snip>
>
> I've sure seen a lot of questions about the flattening of lists. I found
> this version of flatten somewhere, I thought I got it from the Python
> Cookbook but I can't find it now. Perhaps it was posted here on c.l.py.

I
> *don't* claim authorship, I'm merely an admirer of such a clean-looking
> solution.
>
> def flatten(a):
> if not isinstance(a, (tuple,list)): return [a]
> if len(a)==0: return []
> return flatten(a[0])+flatten(a[1:])
>
> a = [[1, 2, 4], 4, 5, [2, 3], 6, [6], [], 'askjdf']
>
> print len(flatten(a))
>
> gives the value 10.
>
> Considering how often this comes up, might there be a place for some sort

of
> flatten() routine in the std dist, perhaps itertools?
>
> -- Paul
>
>

It's me, Jan 12, 2005
6. ### It's meGuest

Oh, darn. I asked this kind of question before. <plonk, plonk>

def flatten(seq):
for x in seq:
if hasattr(x, "__iter__"):
for subx in flatten(x):
yield subx
else:
yield x

data = [[1,5,2],8,4]
val_to_pos = {}
for i, x in enumerate(flatten(data)):
val_to_pos[x] = i + 1
print val_to_pos

"It's me" <> wrote in message
news:ukdFd.10645\$...
> Okay, I give up.
>
> What's the best way to count number of items in a list?
>
> For instance,
>
> a=[[1,2,4],4,5,[2,3]]
>
> I want to know how many items are there in a (answer should be 7 - I don't
> want it to be 4)
>
> I tried:
>
> b=len([x for y in a for x in y])
>
> That doesn't work because you would get an iteration over non-sequence.
>
> I tried:
>
> g=lambda x: (1,len(x))[isinstance(x,(list,tuple,dict))]
> b=sum(lambda(x) for x in a)
>
> and that didn't work because I get a TypeError from the len function

(don't
> know why)
>
> I can, of course:
>
> i=0
> for x in a:
> if isinstance(x,(list,tuple,dict)):
> i += len(x)
> else:
> i += 1
>
> but that's so C-like...
>
> Thanks,
>
>

It's me, Jan 12, 2005
7. ### AnthonyGuest

On Wed, 12 Jan 2005 17:42:50 GMT, It's me <> wrote:
> Okay, I give up.
>
> What's the best way to count number of items in a list?

How long is a piece of string? There are many different ways, which

> For instance,
>
> a=[[1,2,4],4,5,[2,3]]
>
> I want to know how many items are there in a (answer should be 7 - I don't
> want it to be 4)
>
> I tried:
>
> b=len([x for y in a for x in y])
>
> That doesn't work because you would get an iteration over non-sequence.

> I tried:
>
> g=lambda x: (1,len(x))[isinstance(x,(list,tuple,dict))]
> b=sum(lambda(x) for x in a)
>
> and that didn't work because I get a TypeError from the len function (don't
> know why)

Because you're trying to get the length of an integer, which is what's failing.

If you know that the list nesting is only one deep, you can do something like:

===
#!/usr/local/bin/python

compoundList = [[1,2,4],4,5,[2,3]]

listLengths = [len(item) for item in compoundList if type(item) not in
[int,long,str,float]]
print listLengths

compoundLength = len(compoundList) - len(listLengths) + sum(listLengths)
print compoundLength
===

If the nesting is 2 deep or more, then the next two options that I
would explore would be:

1. Have a look in the standard library. I'm pretty sure that there are
list-manipulation libraries that'll do what you want (not sure on
names, though).
2. Write a function to do what you want. Some sort of recursive thing
should be pretty easy to write. Of course it depends on how fast you
need to go, but that should give you a good first approximation.

Anthony

--
-----------------------------------------------------
HyPEraCtiVE? HeY, WhO aRE YoU cALliNg HypERaCtIve?!

-----------------------------------------------------

Anthony, Jan 12, 2005
8. ### It's meGuest

Yes, Mark, I came up with almost the same code (after reading back old

def flatten(seq):
for x in seq:
if hasattr(x, "__iter__"):
for subx in flatten(x):
yield subx
else:
yield x

def count_item(data):
return len([(i,x) for i, x in enumerate(flatten(data))])

data = [[1,5,2],8,4]
print count_item(data)

Thanks everybody.

"Mark McEahern" <> wrote in message
news:...
> It's me wrote:
>
> >Okay, I give up.
> >
> >What's the best way to count number of items in a list [that may contain

lists]?
> >
> >

> a = [[1,2,4],4,5,[2,3]]
>
> def iterall(seq):
> for item in seq:
> try:
> for subitem in iterall(item):
> yield subitem
> except TypeError:
> yield item
>
> all = [x for x in iterall(a)]
> print len(all)
>

It's me, Jan 12, 2005
9. ### Steven BethardGuest

Mark McEahern wrote:
> It's me wrote:
>
>> Okay, I give up.
>>
>> What's the best way to count number of items in a list [that may
>> contain lists]?
>>
>>

> a = [[1,2,4],4,5,[2,3]]
>
> def iterall(seq):
> for item in seq:
> try:
> for subitem in iterall(item):
> yield subitem
> except TypeError:
> yield item
>
> all = [x for x in iterall(a)]
> print len(all)
>

Beware:

py> list(iterall(['a']))
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
File "<interactive input>", line 4, in iterall
...
File "<interactive input>", line 4, in iterall
RuntimeError: maximum recursion depth exceeded

You need to special-case strings. I would do this explicitly, e.g.:

py> def iterall(seq):
.... for item in seq:
.... if isinstance(item, basestring):
.... yield item
.... else:
.... try:
.... for subitem in iterall(item):
.... yield subitem
.... except TypeError:
.... yield item
....
py> list(iterall(['a']))
['a']

but you can also do this by checking for __iter__ as in one of the other
posted solutions. (This takes advantage of the fact that strings use
the __getitem__ protocol for iteration instead of __iter__.)

Steve

Steven Bethard, Jan 12, 2005
10. ### Bernhard HerzogGuest

"It's me" <> writes:

> May be flatten should be build into the language somehow....

That shouldn't be necessary as it can easily be written in a single list
comprehension:

a = [[1,2,4],4,5,[2,3]]
flat_a = [x for cur, rest in [[a[:1], a[1:]]] for x in cur
if (not isinstance(x, (list, tuple))
and (not rest or not cur.append(rest.pop(0)))
or (x and (cur.append(x[0]) or rest.__setslice__(0, 0, x[1:])))
or (not x and rest and cur.append(rest.pop(0))))]

;-)

Bernhard

--
Intevation GmbH http://intevation.de/
Skencil http://skencil.org/
Thuban http://thuban.intevation.org/

Bernhard Herzog, Jan 12, 2005
11. ### Michael HartlGuest

There's a great function called "walk" at that iterates over arbitrary
data (and is recursion-proof) at

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/118845

It also supplies a recursion-proof way to flatten a list. (Once you
can iterate over an arbitrary sequence, the flattened version is just
[element for element in walk(sequence)].) I use both functions all the
time.

Adding a flatten function (along with walk) to Python sounds like a
good idea to me. Having used Mathematica for many years, which uses
Flatten[] all over the place, I was actually quite surprised to find
that Python didn't have it.

Michael

Michael Hartl, Jan 12, 2005
12. ### Leif K-BrooksGuest

Paul McGuire wrote:
> Considering how often this comes up, might there be a place for some sort of
> flatten() routine in the std dist, perhaps itertools?

A problem I see is that itertools tries to work across all iterable
types, but flattening can't always be a generalized operation. For
instance, a naive flattening function might turn the list ['foo', 'bar']
into ['f', 'o', 'o', 'b', 'a', 'r'] -- or worse, fall into infinite
recursion -- when the intended result would be to leave the list
unchanged. Of course, a generalized flattening function could take an
argument listing types to ignore, but that can get very complicated very
fast.

Leif K-Brooks, Jan 12, 2005
13. ### Steven BethardGuest

Michael Hartl wrote:
> (Once you can iterate over an arbitrary sequence, the
> flattened version is just
> [element for element in walk(sequence)].)

Or, better yet:

list(walk(sequence))

Steve

Steven Bethard, Jan 12, 2005
14. ### Michael HartlGuest

That's cool! Of course, walk returns a generator, so using a list
comprehension to turn it into a list seems natural, but I didn't
realize that list() does the same thing (and neither, apparently, did
the original implementor) -- although, with a little reflection, it
obviously must!

Michael

Michael Hartl, Jan 12, 2005
15. ### Steven BethardGuest

list and generators (WAS: counting items)

Michael Hartl wrote:
> That's cool! Of course, walk returns a generator, so using a list
> comprehension to turn it into a list seems natural, but I didn't
> realize that list() does the same thing (and neither, apparently, did
> the original implementor) -- although, with a little reflection, it
> obviously must!

Yup. Also worth noting is that if you want the scoping rules of
generator expression, but need a list instead, you can just call list
with the generator expression:

py> x
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
NameError: name 'x' is not defined
py> [pow(x, 7, 23) for x in range(10)]
[0, 1, 13, 2, 8, 17, 3, 5, 12, 4]
py> x
9
py> del x
py> x
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
NameError: name 'x' is not defined
py> list(pow(x, 7, 23) for x in xrange(10))
[0, 1, 13, 2, 8, 17, 3, 5, 12, 4]
py> x
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
NameError: name 'x' is not defined

Note that with the generator expression, 'x' doesn't get leaked to the
enclosing scope.

Steve

Steven Bethard, Jan 12, 2005
16. ### Bengt RichterGuest

On Wed, 12 Jan 2005 18:07:47 GMT, "Andrew Koenig" <> wrote:

>"It's me" <> wrote in message
>news:ukdFd.10645\$...
>
>> What's the best way to count number of items in a list?
>>
>> For instance,
>>
>> a=[[1,2,4],4,5,[2,3]]
>>
>> I want to know how many items are there in a (answer should be 7 - I don't
>> want it to be 4)

>
>
> def totallen(x):
> if isinstance(x, (list, tuple, dict)):
> return sum(map(totallen, x))
> return 1

Since the requirement is to _count_, not flatten, ISTM your solution is best so far ;-)

Regards,
Bengt Richter

Bengt Richter, Jan 13, 2005
17. ### Craig RingerGuest

On Wed, 2005-01-12 at 20:10 +0100, Bernhard Herzog wrote:
> "It's me" <> writes:
>
> > May be flatten should be build into the language somehow....

>
> That shouldn't be necessary as it can easily be written in a single list
> comprehension:
>
> a = [[1,2,4],4,5,[2,3]]
> flat_a = [x for cur, rest in [[a[:1], a[1:]]] for x in cur
> if (not isinstance(x, (list, tuple))
> and (not rest or not cur.append(rest.pop(0)))
> or (x and (cur.append(x[0]) or rest.__setslice__(0, 0, x[1:])))
> or (not x and rest and cur.append(rest.pop(0))))]
>
> ;-)

If it means I _never_ have to see that list comprehension again, then
seeing 'flatten' go into itertools would make me very, very happy

--
Craig Ringer

Craig Ringer, Jan 13, 2005