orange orange - 3 months ago 21
Python Question

Lazy evaluation of variables

I want to lexicographically compare two lists, but the values inside the list should be computed when needed. For instance, for these two lists

a = list([1, 3, 3])
b = list([1, 2, 2])

(a < b) == False
(b < a) == True


I'd like the values in the list to be functions and in the case of
a
and
b
, the values (i.e. the function) at index=2 would not be evaluated as the values at index=1 (
a[1]==3, b[1]==2
) are already sufficient to determine that
b < a
.

One option would be to manually compare the elements, and that's probably what I will do when I don't find a solution that allows me to use the list's comparator, but I found that the manual loop is a tad slower than the list's builtin comparator which is why I want to make use of it.

Update

Here's a way to accomplish what I am trying to do, but I was wondering if there are any built-in functions that would do this faster (and which makes use of this feature of lists).

def lex_comp(a, b):
for func_a, func_b in izip(a, b):
v_a = func_a()
v_b = func_b()
if v_a < v_b: return -1
if v_b > v_a: return +1
return 0


def foo1(): return 1
def foo2(): return 1

def bar1(): return 1
def bar2(): return 2

def func1(): return ...
def func2(): return ...

list_a = [foo1, bar1, func1, ...]
list_b = [foo2, bar2, func2, ...]

# now you can use the comparator for instance to sort a list of these lists
sort([list_a, list_b], cmp=lex_comp)

Answer

Here is an approach that uses lazy evaluation:

>>> def f(x):
...   return 2**x
... 
>>> def g(x):
...   return x*2
... 
>>> [f(x) for x in range(1,10)]
[2, 4, 8, 16, 32, 64, 128, 256, 512]
>>> [g(x) for x in range(1,10)]
[2, 4, 6, 8, 10, 12, 14, 16, 18]
>>> zipped = zip((f(i) for i in range(1,10)),(g(i) for i in range(1,10)))
>>> x,y = next(itertools.dropwhile(lambda t: t[0]==t[1],zipped))
>>> x > y
True
>>> x < y
False
>>> x
8
>>> y
6
>>>