counting items

I

It's me

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,
 
A

Andrew Koenig

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)

How about this?

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

Paul McGuire

It's me said:
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
 
M

Mark McEahern

It's me said:
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)
 
I

It's me

Thanks.

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


Paul McGuire said:
It's me said:
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
 
I

It's me

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

Somebody posted an answer before:

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
 
A

Anthony

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
give you different trade offs.
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.

And is very unreadable.
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
 
I

It's me

Yes, Mark, I came up with almost the same code (after reading back old
answers from this list):

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 said:
It's me said:
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)
 
S

Steven Bethard

Mark said:
It's me said:
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
 
B

Bernhard Herzog

It's me said:
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
 
M

Michael Hartl

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
 
L

Leif K-Brooks

Paul said:
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.
 
S

Steven Bethard

Michael said:
(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
 
M

Michael Hartl

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
 
S

Steven Bethard

Michael said:
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
 
B

Bengt Richter

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)

How about this?

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
 
C

Craig Ringer

It's me said:
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 :p
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top