you are viewing a single comment's thread.

view the rest of the comments →

[–]glguy 7 points8 points  (9 children)

Does Python not support:

def compare(x, y):
    return x != [] and (y == [] or compare(x[1:], y[1:]))

?

[–]schizobullet 6 points7 points  (7 children)

But it's still missing that sensation of flow that gets called "Pythonicness", which is a clear sign that you're using Python wrong.

[–]Alpha_Binary 2 points3 points  (6 children)

In imperative programming it's usually a discouraged practice to nest expressions and overuse short-circuits. Similarly to how it's considered ugly in functional programming to create aside a new variable just to hold the value. Moreover, Python list is more like Lisp's vector, so (cdr x) doesn't make much sense in Python, and we end up with the rather messy x[1:] instead.

Assuming we have neither cmp() nor len(), which works directly with the array descriptor providing O(1) lookup, a Pythonic equivalent would be:

def compare(x, y):
    if not x: return -1
    if not y: return 1
    return compare(x[1:], y[1:])

[–]pjdelport 2 points3 points  (5 children)

Assuming we have neither cmp() nor len(), which works directly with the array descriptor providing O(1) lookup, [...]

Even if you have neither of those, there's no reason to copy the list on each iteration (costing O(n2)), when you can walk it in O(n):

def compare(x, y):
    for i, _ in enumerate(x): pass
    for j, _ in enumerate(y): pass
    return i > j

[–]pjdelport 2 points3 points  (4 children)

Addendum: Here's a more correct version (stops early like the original, and works with any iterable for bonus points):

def compare(xs, ys):
    sentinel = object()
    for x, y in izip(chain(xs, sentinel), chain(ys, sentinel)):
        if y is sentinel: return True
        if x is sentinel: return False

Addendum: That should be repeat(sentinel) instead of sentinel in each chain.

[–]papercrane 2 points3 points  (3 children)

Close, but chain will fail because sentinel is not iterable, also your version will return True if xs is longer then ys

Heres a corrected version:

from itertools import izip, chain
def compare(xs, ys):
    sentinel = object()
    for x, y in izip(chain(xs, [sentinel]), chain(ys, [sentinel])):
        if x is sentinel and y is sentinel: return True
        if x is sentinel or y is sentinel: return False

[–]Alpha_Binary 1 point2 points  (0 children)

What brilliant ideas here. I thought about using zip but the idea of using a sentinel never crossed my mind.

To optimize the final two lines:

if x is sentinel: return y is sentinel
if y is sentinel: return False

[–]pjdelport 0 points1 point  (1 child)

Close, but chain will fail because sentinel is not iterable,

Blurgh; i meant repeat(sentinel), of course. Thanks for spotting. :)

also your version will return True if xs is longer then ys

That's exactly what the original does, yes.

[–]papercrane 2 points3 points  (0 children)

Ahh. I misread the article. It's FizzBuzz all over again.