orange - 2 months ago 6x

Python Question

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`

`b`

`a[1]==3, b[1]==2`

`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

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
>>>
```

Source (Stackoverflow)

Comments