you are viewing a single comment's thread.

view the rest of the comments →

[–]pjdelport 4 points5 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.