[newbie] Recursive algorithm - review

Wiktor look at signature.invalid
Sat Jan 4 06:09:00 EST 2014


On Sat, 4 Jan 2014 13:02:37 +1100, Chris Angelico wrote:

>> def check(towers, x=None):
>>         column = []                               # value added on pos. x
>>         for i in range(len(towers)):
>>             column.append(towers[i][c])
>>         column = [x for x in column if x != 0]
> 
> Any time you iterate over range(len(something)), you probably want to
> iterate over the thing instead:
> 
> for t in towers:
>     column.append(t[c])

  Right, /facepalm/ I've done it so many times. Don't know why not this time.
 
> And any time you iterate over something and append to another list,
> you probably want a list comprehension:
> 
> column = [t[c] for t in towers]
> [...]
> column = [t[c] for t in towers if t[c] != 0]
> [...]
> column = [t[c] for t in towers if t[c]]

  Nice.
 
>>         for c in range(len(towers)):              # 'x' not provided,
>>             column = []                           # so check all columns
> 
> I wouldn't normally wrap a comment onto an unrelated line; I'd put the
> comment above the loop, since it's too long to be a part of the loop
> header itself. It goes as much with the "else" as with the loop,
> anyhow.

  My mistake. I know, that sometimes comment doesn't relate to line that is
next to, but for one second I belived that it would be more readable ('talk'
about the code whitout providing more unnecessary whitespace). Now I see that
it isn't.   

> This is one case where you probably _do_ want to iterate up to
> range(len(towers)), though, which is why I said "probably" above. :)
> 
>>             for i in range(len(towers)):
>>                 column.append(towers[i][c])
>>             column = [x for x in column if x != 0]
> 
> This is the same code you had above, so it can benefit from the same
> translation. But maybe it'd be even cleaner to simply call yourself?
> 
> if not check(towers, i): return False

  You're right. It's cleaner this way.
 
>>             # print(column)
>>             if len(column) != len(set(column)):
>>                 return False
>>         return True
> 
> And in fact, you might want to turn this whole branch into something
> that harks to a more functional programming style:
> 
> return all((check(towers, i) for i in range(len(towers)))

  Great. I didn't know all() before. :-)
  Now check() function looks very neat. 
  Although 'if' statement must now looks like: 'if x is not None:'. Earlier x
never was going to be 0. Now it can be.
 
>>         random.shuffle(row)                    # at every recursion
> 
> Again, I wouldn't wrap comments onto unrelated lines. You see how
> confusing this looks, now that I take this line out of context? Same
> will happen if it throws an exception.

  Yeap. Now I see it. Never gonna do that again. :-)
 
> When you multiply a list of lists, you get references to the same
> list, yes. But you could use multiplication for one level:
> 
> towers = [[0]*size for _ in range(size)]
> 
> That'll give you independent lists. 

  Got it!

>>     if not row:
>>         row = [a for a in range(1, size+1)]
>>         random.shuffle(row)
> 
> This is the same as you have at the top of 'if not towers'. Can you be
> confident that row is None any time towers is None? If so, just move
> this up above the other check and save the duplication.

  row is None at start, but later it is list - sometimes an empty list. For
that cases this if statement was written. If row == [] -> generate new random
row that I can pop out from.
 
>>             num = row.pop(0)                   # take num from right, and
>>             towers[x // size][x % size] = num  # if doesn't match - put
>>             repeat = not check(towers, x)      # back (append) on left -
>>                                                # - to rotate
>>             if repeat:                       # I'll repeat 'matching' next
>>                 row.append(num)              # number as long as last
>>                 x -= 1                       # changed column is unique
> 
> Hmm, I'm slightly confused by your comments here. You pop(0) and
> append(), and describe that as taking from the right and putting on
> the left. Normally I'd write a list like this:

  Of course, of course. I was thinking one, writing another. I switched left
and right in my explanation. It looks stupid now. ;-)

  Thank you for all Your comments.

-- 
Best regards,     Wiktor Matuszewski
'py{}@wu{}em.pl'.format('wkm', 'ka') # email spam trap



More information about the Python-list mailing list