orange orange -4 years ago 168
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
, 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.


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 Source

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
>>> x < y
>>> x
>>> y
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download