4 ms·
>I love Ruby because I never feel like I'm programming in it, it almost feels like pseudo code that's not going to actually execute. Uh, you realise that descr
by anthonyb 16y ago
>I love Ruby because I never feel like I'm programming in it, it almost feels like pseudo code that's not going to actually execute.
Uh, you realise that describes any high level language, right? Ruby scores pretty low on the readability scale, about halfway between Perl and Python, but I find it's more familiarity with a particular language that determines how readable people find things.
Here's a quick Python version. The main thing to notice is that while the overall flow/structure is similar, I don't have a lot of { } << \ characters hanging around, and I don't have to chain blocks together since I have list comprehensions.
from collections import defaultdict
customer_file = (line.strip().split(',') for line in file('customers.txt'))
grouped_ages = defaultdict(list)
for name, age in customer_file:
grouped_ages[age].append(name)
age_lengths = sorted( [(len(names), age) for age, names in grouped_ages.items()], reverse=True )
for length, age in age_lengths[:3]:
print "%s years old: %s customers" % (age, length)
- ataggart 16y ago>Uh, you realise that describes any high level language, right? I'm inclined to agree. I think the following also pretty closely matches the english requirements. (with-open [rdr (reader "customers.txt")] (->> (line-seq rdr) (map #(second (.split % ","))) (group-by identity) (map (fn [[age coll]] [age (count coll)])) (sort-by second (comparator >)) (map first) (take 3)))
- anthonyb 16y agoLooks kinda nasty to me, but then I'm not too familiar with Clojure/Lisp/whatever-the-hell-that-is ;) I think one of the side effects of learning a Lisp is that you get a bit blasé about using map. Do you find list comprehensions easier than map/filter? Is there a list comprehension equivalent in Lisp, or would you have to write your own?
- ataggart 16y agoIt's clojure. 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 ;)
- anthonyb 16y agoWell, 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 ;) ;)
- ataggart 16y agoNote, 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.
- 16y ago
- anthonyb 16y agoA meta-question: why do people keep downvoting this comment? It's been up and down ever since I posted it. Is it that I'm critical of Ruby? I would've thought that if I take the time to write some code and respond in a rational way, then it should be worth at least a couple of karma. What gives?
- nwmcsween 16y agoWhere is this readability scale? Would you mind giving a link for it, I wouldn't mind seeing how the 'readability' statistics came to be.
- ashleyw 16y agoWell, I was comparing it to something like Java. Though Python still scores far lower on my readability scale. It's seems like it's halfway to being minified, the lines are chock-a-block. Also, this is a better version in Ruby: file = File.open('customers.txt') customers = {} file.each_line do |line| name, age = line.split(",") customers[age.to_i] ||= [] customers[age.to_i] << name end grouped = customers.sort_by{|age, names| names.count}.reverse grouped.first(3).each do |age, customers| puts "#{age} years old: #{customers.count} customers" end …not sure what I was thinking before, it was late.
- anthonyb 16y ago> Python still scores far lower on my readability scale. It's seems like it's halfway to being minified, the lines are chock-a-block. That's likely because you're not used to reading Python. For me, Ruby seems unreadable - you have all these weird << and ||= assignments, {||} blocks, etc. I don't parse those as well, because I don't program much Ruby. I'm sure if I did, it'd make a lot more 'intuitive' sense - ditto for you and Python's list comprehensions.
- nwmcsween 16y ago<< and >> are rudimentary it's almost always exactly the same as unix dated from 1970's redirection. e.g: $ echo 'crap' >> somefile.txt. ||= reads as 'or equal', simple.
- anthonyb 16y agoYeah, I know what they do - eg. ||= being a Ruby idiom for 'set if this currently evaluates as false'. The point is that because I don't often program in Ruby, it's less readable (for me). Similarly, if you're not used to list comprehensions they'll seem opaque - but I use them all the time, and find them far more readable than equivalent expressions using map/filter. That said, I do find the more "squiggly" languages (Perl, Ruby, C) to be less readable than the equivalent Scheme or Python, and I suspect that it's because there are fewer weird characters, so it's closer to English.
- irahul 16y agoThe groupby, if done using itertools, will cut some code. from itertools import groupby customer_data = (line.strip().split(',') for line in file('customer.txt')) grouped_ages = groupby(customer_data, key=itemgetter(1)) print sorted((len(list(g)), k) for k, g in grouped_ages)[-3:]
- anthonyb 16y agoAh yes, I'd forgotten about groupby. You'll also need to do a from operator import itemgetter as well.