1

In Python 2.7.x I have two lists I would like a function that returns the first value (not index) as shown below

def first_incorrect_term(polynomial, terms):
    for index in range(len(polynomial), len(terms)):
        if evaluate(polynomial, index) != terms[index-1]:
            return evaluate(polynomial, index)

Let us assume evaluate is a function that works. I would like to replace these three lines which looks Object Oriented into something that uses the "find" or some such function in Python.

Basically I am iterating through the indices of the second list beyond the number terms in the polynomial (as I am confident the first X terms will match), evaluating it and comparing with the expected terms. For the first instance where the terms do not match I would like the evaluated polynomial returned.

I am looking for a replacement of these 3 lines using a Python find/lambda or some such thing, this is because I can definitely see I am not using the Python power as described for example in the link

PS: This is somewhat related to a Project Euler problem, however I have solved it using the snippet above and would like to improve my "Python" skills :)

Kannan Ekanath
  • 16,759
  • 22
  • 75
  • 101
  • 4
    `for index in range(len(polynomial), len(terms))` will not iterate over the indices of polynomial, but over the indices of terms beyond the end of polynomial (poly is 5 elements, terms is 7 elements gives `range(5,7) = [5,6]`); that doesn't mesh with your description of 'iterating through the indices of the first list'. – Phil H Nov 09 '12 at 11:20
  • Regarding what you actually want; are you looking for something you can iterate over? – Phil H Nov 09 '12 at 11:21
  • You are right let me edit it – Kannan Ekanath Nov 09 '12 at 11:22
  • I am looking for a "functional" replacement of this Object Oriented like code that uses the python power ! – Kannan Ekanath Nov 09 '12 at 11:24
  • 1
    There are no apparent objects here, nor methods being called, so it is already 'functional' to some degree... can you be a bit more specific? – Phil H Nov 09 '12 at 11:29
  • @PhilH What I actually meant was I seem to be instructing iterations, evaluations, comparisons which is what you would do in Java/C etc. If you look at the link http://tomayko.com/writings/cleanest-python-find-in-list-function something similar to that is what I am after. Hope tha tmakes sense – Kannan Ekanath Nov 09 '12 at 11:45

2 Answers2

1

Firstly, use yield to make a generator version of your function:

def incorrect_terms(polynomial, terms):
    for index in range(len(polynomial), len(terms)):
        eval = evaluate(polynomial,index)
        if eval != terms[index-1]:
            yield (polynomial, index, eval)

Then the first result is the first mismatch:

mismatches = incorrect_terms(polynomial, terms)
first_mismatch = mismatches.next()

I think you actually want to iterate over all the values of terms, not the values after polynomial's length, in which case you can zip:

results = (evaluate(polynomial,index) for index in count(0))
pairsToCompare = itertools.izip(results, terms)
mismatches = (pair for pair in pairsToCompare if pair[0] != pair[1])

first_mismatch = mismatches.next()

Assuming here that evaluate(polynomial, n) is calculating the nth term for a given polynomial, and that these are being compared with the values in terms.

Phil H
  • 19,928
  • 7
  • 68
  • 105
  • Phil I definitely want to evaluate from a point and not zero as evaluating is not a trivial function and is somewhat expensive. Also I don't want to compute all evaluations because as N increases the time taken to evaluate increases. So I would prefer stopping at the earliest available oppurtunity – Kannan Ekanath Nov 09 '12 at 11:47
  • @CalmStorm: All the approaches shown here are lazily evaluated, that is they only evaluate the values one at a time -- izip doesn't evaluate the next thing for the zip until it is asked for. Regarding evaluation from zero or not: I can only guess at the `evaluate` function; it seemed plausible that you are evaluating the terms in a polynomial and comparing them. In that case, I expected you to need to compare all the terms, from the first, but stopping when you find a discrepancy. If that is not the case, go with the first version. – Phil H Nov 13 '12 at 12:25
  • The question is very useful as well in this context http://stackoverflow.com/questions/8534256/python-find-first-element-in-a-sequence-that-matches-a-predicate – Kannan Ekanath Nov 23 '12 at 13:25
0

I would do it using generator expressions, but they don't fit in one line as well:

def first_incorrect_term(polynomial, terms):
    evaled = ((index, evaluate(polynomial, index)) for index in range(len(polynomial), len(terms)))
    return next((val for index, val in evaled if val != terms[index-1]), None)
glglgl
  • 89,107
  • 13
  • 149
  • 217