trictionary?

Adam Tomjack adamtj at adamtj.org
Mon Aug 29 00:14:04 EDT 2005


I'd write it like this:

    bin = {}
    for start, end, AS, full in heard:
       week = int((start-startDate)/aWeek)
       counters = bin.setdefault(week, [0, 0])
       if full:
          counters[0] += 1
       else:
          counters[1] += 1

    for week, (times_full, times_not_full) in bin.iteritems():
       print ...

Seriously, use setdefault() as often as you can.  It may be a little 
awkward at first, but after a little bit, you instantly know what it 
means.  It takes out a whole if/else statement which will make your code 
smaller and more readable at the same time.

The list is actually representing a struct.  Regardless of how it 
smells, it's tight, small, and elegant.  (This is the sort of problem 
where Python shines.)  I do stuff like this all the time.  Lists are so 
lightweight that there really isn't a better way to solve this problem. 
  Anything else either involves more code or is less readable, in my 
opinion.

Using an idea you used earlier, you could get smaller code by saying:
    for start, end, AS, full in heard:
       week = int((start-startDate)/aWeek)
       counters = bin.setdefault(week, [0, 0])
       counters[not full] += 1

Or
    for start, end, AS, full in heard:
       week = int((start-startDate)/aWeek)
       bin.setdefault(week, [0, 0])[not full] += 1

Or even
    for start, end, AS, full in heard:
      bin.setdefault(int((start-startDate)/aWeek), [0, 0])[not full] += 1

While smaller, those are all too tricky for my taste.  I think they're 
harder to read.  I'd personally use the if/else.  YMMV.


Using lists to represent structs is perfectly fine if the list doesn't 
live longer than about one screen of code.  If the list-struct gets 
returned from a top-level function and gets used elsewhere, then you 
should start to worry.  It's too easy to forget what each element is 
supposed to represent if you have to scroll your editor to see the place 
where the list was created.  That, in my opinion, would smell fishy.  In 
that case, you should probably represent your struct with a class or a 
dict so that each element has a name.  On the flip side, using such a 
heavy solution for such a simple problem also smells bad.  The solution 
should should be as complicated as the problem -- no more, no less.

Adam


Randy Bush wrote:
>>>    bin = {}
>>>    for whatever:
>>>       for [a, b] in foo:
>>>	  x = 42 - a
>>>	  if bin.has_key(x):
>>>	     bin[x.b] += 1
>>>	  else:
>>>	     bin[x.b] = 1
>>>	     bin[x.not b] = 0
>>>    for x, y, z in bin.iteritems():
>>>       print x, y, z
>>>
>>>should the dict value become a two element list, or is there a
>>>cleaner way to do this?
>>
>>It would probably help if you explained what the real problem is
>>you're trying to solve.
> 
> 
> actually, that code fragment was meant to do that.  it's pretty much
> what i needed to do at that point, just the variable names made
> simple.
> 
> 
>>Using a two element list to store a pair of counts has a bad code
>>smell to me.
> 
> 
> exactly.  which is why i was asking.
> 
> 
>>That said, you could write your code something like:
>>     bin = {}
>>     for whatever:
>>        # NOTE: brackets are unnecessary
>>        for a, b in foo:
>>	  x = 42 - a
>>           # NOTE: 'in' is generally faster than has_key()
>>	  if x in bin
>>	     bin[x][0] += 1
>>	  else:
>>              bin[x] = [1, 0]
>>     # NOTE: extra parens necessary to unpack count list
>>     for x, (y, z) in bin.iteritems():
>>        print x, y, z
> 
> 
> so, to do this using the real names, it looks like
> 
>    for [start, end, AS, full] in heard:
>       week = int((start-startDate)/aWeek)
>       if week in bin:
>          if full:
> 	    bin[week][0] += 1
> 	 else:
> 	    bin[week][1] += 1
>       else:
>          if full:
> 	    bin[week] = [1, 0]
> 	 else:
> 	    bin[week] = [0, 1]
>    ...
>    for i, (j, k) in bin.iteritems():
>       if j == 0:
> 	 print str(i) + ",," + str(k)
>       elif k == 0:
> 	 print str(i) + "," + str(j)
>       else:
> 	 print str(i) + "," + str(j) + "," + str(k)
> 
> which is still pretty darned grotty and unexpressive.  of course,
> i could be a bit more obscure and do
> 
>       if week in bin:
>          bin[week][not full] += 1
>       else:
>          bin[week] = [ full, not full ]
> 
> except i probably have to coerce the types or something.  less
> code but less obvious.
> 
> randy
> 




More information about the Python-list mailing list