As for preference, given that map, filter, etc., are lazy, I like the clear visibility of each step working on each element of the sequence.
Clojure has a list comprehension, for, though using it here is more trouble than it's worth since you have to group and sort, both of which require you to step outside the comprehension and work on the whole list; that's why your code has multiple sections.
Instead, I see the example as just a selection/transformation process on sequences of data. Each step in the clojure code takes and returns a sequence of values (the ->> macro weaves them together):
0. a sequence of lines from a file
1. a sequence of age strings
2. a sequence of [age, [ages...]] tuples
3. a sequence of [age, count] tuples
4. a sequence of [age, count] tuples sorted by count desc
5. a sequence of age strings
6. a sequence of up to 3 age strings
Fun detail: The with-open macro is akin to python's with statement, supports arbitrary number of items, is closed in reverse order of their appearance, and didn't require a change to the language to implement ;)
I wanted to reply to anthonyb's comment about macro use changing the language in the clojure example but couldn't, I guess because it's too deeply nested.
Anyway, ataggart didn't write a macro he just used one that's already part of the language. Using a macro does not count as changing the language.
He was talking about with-open not needing a change to the language to implement. In other words, Python's with statement did need a change to the language, but then Python is a (semi-)interpreted language written in C, so it's a cheap shot - just what I'd expect from a dirty Lisp hacker ;)
Well, you need to sort by occurrences, so you have to work with the whole list in this particular case. I also don't think that having two sections is a particularly big deal, since semantically you're working with two separate things too (the list of people+ages, and the aggregated list of names+a count). If you wanted to do something else too (say, list the names as well) then having an intermediate form can come in handy.
Also, I'm pretty sure that writing a macro counts as 'changing the language', although that line's a bit blurred when you're talking about lisps ;) ;)
Note, I wasn't criticizing the python implementation. It's a perfectly reasonable way to model the problem.
You brought up list comprehensions, and something about being "blasé about using map". I wanted to show how a different way of modeling the problem yields a different structure to the code (namely, as a chain of transformations on sequences).
One is not better or worse than another. One of the things I enjoyed most about learning clojure was forcing myself to think in these different ways.
As for preference, given that map, filter, etc., are lazy, I like the clear visibility of each step working on each element of the sequence.
Clojure has a list comprehension, for, though using it here is more trouble than it's worth since you have to group and sort, both of which require you to step outside the comprehension and work on the whole list; that's why your code has multiple sections.
Instead, I see the example as just a selection/transformation process on sequences of data. Each step in the clojure code takes and returns a sequence of values (the ->> macro weaves them together):
Fun detail: The with-open macro is akin to python's with statement, supports arbitrary number of items, is closed in reverse order of their appearance, and didn't require a change to the language to implement ;)