0

Python beginner here. I'm attempting to write a very simple function that calculates an approximate numerical derivative for an expression represented by an input array (or "List" here). I've written this function in matlab and it works fine, but python is confusing me by throwing an indexing error. Here's my attempt:

def diffr(h, myList = []):

    d = []; 

    for n in myList:
        if myList.index(n) > 0:
            print(myList.index(n))
            d_elem = (myList[n] - myList[n-1])/h
            d.append(d_elem)

    return d

The idea is to subtract myList(n-1) from myList(n) and divide by h, and go down the list. I realize that on the first iteration, myList(n-1) will be out of bounds, which is why i put the if clause to check for that condition. But python throws this error after only 5 iterations:

IndexError: list index out of range

pointed at the d_elem line. Funny thing is when i comment out that line and just have the loop print the indices, it goes through the loop just fine. What gives? thanks in advance.

kecer
  • 3,031
  • 2
  • 21
  • 24
mik
  • 110
  • 8
  • I think it would be better to use an enumerate so that you can actually have an iterator. That way you can do 'if idx > 0:' instead of 'if myList.index(n) > 0'. See: http://stackoverflow.com/a/522578/1838970 – Clete2 Aug 25 '14 at 19:11
  • The code is missing the way it is called in order to produce the error. Also, there's a superfluous semicolon after `d`. ;) – Ulrich Eckhardt Aug 25 '14 at 19:12
  • 1
    The `for` loop in Python is what's usually known as a **`for each`** loop in other languages. Therefore `n` won't be an *index*, but the actual *elements* of the sequence `myList`. That's why `myList[n]` will give you unexpected results. If `myList` contains integers, some of them *may* be valid indices, some of them may not, – Lukas Graf Aug 25 '14 at 19:14
  • 2
    Not related to your problem, but you should also avoid the `myList=[]` keyword argument. See [“Least Astonishment” in Python: The Mutable Default Argument](http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument). – Lukas Graf Aug 25 '14 at 19:19

3 Answers3

3

You are switching between working with the contents of the list and the index of the list. You intend n to be an index, but the for loop and use of myList.index(n) both treat it as a value stored in the list.

Change your loop to:

for n in range(1, len(myList)):

and it will solve the problem, since n will take values only from 1 to the length of the list minus 1. You won't even need the if statement.

David Robinson
  • 77,383
  • 16
  • 167
  • 187
3

Just use enumerate and use each element starting from the second element:

def diffr(h, myList):
    d = []
    for ind, n in enumerate(myList[1:],1): # first iteration n will be the second element and myList[ind-1]) will be the first
        d_elem = (n - myList[ind-1]) / h
        d.append(d_elem)
    return d

You don't need to specify myList = [] as a parameter, you will be passing in a list and using a list as a default arg is usually not a good idea “Least Astonishment” in Python: The Mutable Default Argument

In for ind, n in enumerate(myList[1:],1), ind is the index of each element, we add 1 as a parameter to specify to start at index 1 so n will be one element ahead of myList[ind-1])

In your code you are using the element to index so if your list had 4 elements and the first number was 4 or greater you would be trying to access an element at an index that did not exist in your list and get an index error straight away.

Community
  • 1
  • 1
Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
0

When you are iterating through list this way, n yields exact value from the list. For example, given you have a list [520, 380], your n will be 520, then 380. list.index(380) will return 1, since [1] is position of 380 in your list. When you are printing myList.index(n), you are getting an index. However, in your next line you are using the value from list (lets say 380) and that is why you are getting index error. list[380] simply does not exist. But, of course, list[list.index(380)] does.

I recommend you either going for enumerate (as Padraic Cunningham said when I was writing this) or storing index in separate variable and use this instead of your n

kecer
  • 3,031
  • 2
  • 21
  • 24