Velocity Reviews > counting items

# counting items

Michael Hartl
Guest
Posts: n/a

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

http://aspn.activestate.com/ASPN/Coo.../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

Leif K-Brooks
Guest
Posts: n/a

 01-12-2005
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.

Steven Bethard
Guest
Posts: n/a

 01-12-2005
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

Michael Hartl
Guest
Posts: n/a

 01-12-2005
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

Steven Bethard
Guest
Posts: n/a

 01-12-2005
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

Bengt Richter
Guest
Posts: n/a

 01-13-2005
On Wed, 12 Jan 2005 18:07:47 GMT, "Andrew Koenig" <(E-Mail Removed)> wrote:

>"It's me" <(E-Mail Removed)> wrote in message
>news:ukdFd.10645\$(E-Mail Removed) om...
>
>> 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

Craig Ringer
Guest
Posts: n/a

 01-13-2005
On Wed, 2005-01-12 at 20:10 +0100, Bernhard Herzog wrote:
> "It's me" <(E-Mail Removed)> 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