[Tutor] Traversing lists or getting the element you want.

spir denis.spir at gmail.com
Mon Feb 3 09:28:12 CET 2014


On 02/02/2014 09:46 PM, Kipton Moravec wrote:
> I am new to Python, and I do not know how to traverse lists like I
> traverse arrays in C. This is my first program other than "Hello World".
> I have a Raspberry Pi and they say Python is the language of choice for
> that little machine. So I am going to try to learn it.

Traversing an array of 'n' float item in C, using index instead of pointer, may 
translate to:
     float item;
     uint i;	// 0 <= i < n !!!
     for (i=0 ; i<n ; ++i) {
         item = items[i];
         // use item
      }
In python there is a range() function (xrange in python2) translating the same isea:
      for i range(n):	# 0 <= i < n !!!
         item = items[i];
         # use item
Works, but this is not the python way. Python also has a builtin *idiom* to 
traverse a list (or any other collection or "traversable"):
     for item in items:
         # use item

> I have data in the form of x, y pairs where y = f(x) and is non linear.
> It comes from a .csv file.
>
> In this case x is an integer from 165 to 660 so I have 495 data sets.
>
> I need to find the optimal locations of three values of x to piecewise
> linear estimate the function.
>
>
> So I need to find i, j, k so 165 < i < j < k < 660 and the 4 line
> segments [(165, f(165)), (i, f(i))], [(i, f(i)), (j, f(j))], [(j, f(j),
> (k, f(k))], [(k, f(k)), (660, f(660))].
>
>
> The value I need to minimize is the square of the difference between the
> line estimate and the real value at each of the 495 points.
>
>
> I can do this in C. To keep it simple to understand I will assume the
> arrays x[] and y[] and minsum, mini, minj, and mink are global.
>
>
> I have not tested this but this is what I came up with in C. Assuming
> x[] and y[] are already filled with the right values.
>
>
> int x[495];
> double y[495];
> max_elements = 495;
> double minsum;
> int mini, minj, mink
>
>
> void minimize(int max_elements)
>
> {
>      minsum = 9999999999999.0; // big big number

This is more or less a logical error (but one very very frequent). What if the 
array is empty? This gives: min(nothing_at_all)=9999999999999.0. min(nothing) is 
undefined, an anomaly or error. You should probably:
* refuse an empty array (the caller should not call the func at all)
* start with the first item as (temporary) min value
(Same for all similar 'reduce' functions.)

I understand you're not writing a simple min func here (instead minimising 
deviations to a hypothetical average) but the thinking pattern is the same. A 
sane min func may look like --i take the opportuity to show you some python code:

def min_nums (nums):
     n = len(nums)
     assert n > 0, "are you kidding?"

     min = nums[0]
     for i in range(2, n):
         num = nums[i]
         if num < min:
             min = num
     return min

nums = [6,4,5,8,3,1,2,7,8]
print(min_nums(nums))
print(min_nums([]))

>      for (i=2; i<max_elements-6;i++)
>          for (j=i+2; j< max_elements -4; j++)
>               for (k=j+2; k< max_elements-2;k++)
>               {
>                  sum = error(0,i);
>                  sum += error(i,j);
>                  sum += error(j,k);
>                  sum += error(k,495)
>
>                  if (sum < minsum)
>                  {
>                      minsum = sum;
>                      mini = i;
>                      minj = j;
>                      mink = k;
>                  }
>               }
> }

You could export in a sub-func the detail computation of the minimised element. 
Then, you could test it apart, and your minimise func would be barely more 
complicated than the one above (mine).

> double error(int istart, int iend)
> {
>
> // linear interpolation I can optimize but left
> // it not optimized for clarity of the function
>
>      int m;
>
>      double lin_estimate;
>
>      double errorsq;
>
>      errorsq = 0;
>
>      for (m=istart; m<iend; m++)

See range() or better "for item in items".

>      {
>          lin_estimate = y[istart] + ((y[iend] – y[istart]) *
>                         ((x[m] – x[istart]) / (x[iend] – x[istart])));
>
>          errorsq += (lin_estimate – y[m]) * (lin_estimate – y[m]);
>      }
>
>      return (errorsq);
>
> }
>
>
>
> At the end the three values I want are mini, minj, mink;
> or x[mini], x[minj], x[mink]
>
>
> So how do I do this (or approach this) in Python?
>
>
> Kip

Apart for the traversing idiom ('range' or 'for...in') the code is similar. (It 
also has '+=' and friends). (According to Guido van Rossum, Python was in fact 
designed to please C/Unix hackers; apart from the indented syntax and some 
idioms, it is indeed very similar, including a number of "unguessable" terms.)

d


More information about the Tutor mailing list