Traversing through variable-sized lists

A

Andrej Mitrovic

Hi,

I couldn't figure out a better description for the Subject line, but
anyway, I have the following:

_num_frames = 32
_frames = range(0, _num_frames) # This is a list of actual objects,
I'm just pseudocoding here.
_values = [0, 1, 2, 3, 4]

I want to call a function of _frames for each frame with a _values
argument, but in a way to "spread out" the actual values.

I would want something similar to the following to be called:

_frames[0].func(_values[0])
_frames[1].func(_values[0])
_frames[2].func(_values[0])
_frames[3].func(_values[0])
_frames[4].func(_values[1])
_frames[5].func(_values[1])
_frames[6].func(_values[1])
_frames[7].func(_values[1])
_frames[8].func(_values[2])
....etc...

Both the _values list and _frames list can be of variable and uneven
size, which is what is giving me the problems. I'm using Python 2.6.

I've tried the following workaround, but it often gives me inaccurate
results (due to integer division), so I had to add a safety check:

num_frames = 32
values = [0, 1, 2, 3, 4]
offset_step = num_frames / len(values)
for index in xrange(0, num_frames):
offset = index / offset_step
if offset > offset_values[-1]:
offset = offset_values[-1]
frames[index].func(values[offset])

There has to be a better way to do this. I'd appreciate any help.
Cheers!
 
M

Matt McCredie

I've tried the following workaround, but it often gives me inaccurate
results (due to integer division), so I had to add a safety check:

num_frames = 32
values = [0, 1, 2, 3, 4]
offset_step = num_frames / len(values)
for index in xrange(0, num_frames):
offset = index / offset_step
if offset > offset_values[-1]:
offset = offset_values[-1]
frames[index].func(values[offset])

There has to be a better way to do this. I'd appreciate any help.
Cheers!

This is how I would do it, assuming you just want to call the remaining frames
with the last value.

from itertools import izip

def stretch(seq, n):
for val in seq:
for i in xrange(n):
yield val
while True:
yield val

frames_per_value = num_frames // len(values)
for frame, value in izip(frames, stretch(values, frames_per_value)):
frame.func(value)


Matt
 
P

Peter Pearson

On Wed, 17 Feb 2010 10:10:37 -0800 (PST), Andrej Mitrovic wrote:
[snip]
_num_frames = 32
_frames = range(0, _num_frames) # This is a list of actual objects,
I'm just pseudocoding here.
_values = [0, 1, 2, 3, 4]

I want to call a function of _frames for each frame with a _values
argument, but in a way to "spread out" the actual values.

I would want something similar to the following to be called:

_frames[0].func(_values[0])
_frames[1].func(_values[0])
_frames[2].func(_values[0])
_frames[3].func(_values[0])
_frames[4].func(_values[1])
_frames[5].func(_values[1])
_frames[6].func(_values[1])
_frames[7].func(_values[1])
_frames[8].func(_values[2])
...etc...

Both the _values list and _frames list can be of variable and uneven
size, which is what is giving me the problems. I'm using Python 2.6.

I've tried the following workaround, but it often gives me inaccurate
results (due to integer division), so I had to add a safety check:

num_frames = 32
values = [0, 1, 2, 3, 4]
offset_step = num_frames / len(values)
for index in xrange(0, num_frames):
offset = index / offset_step
if offset > offset_values[-1]:
offset = offset_values[-1]
frames[index].func(values[offset])

Here's my suggestion:

Python 2.5.2 (r252:60911, Jul 22 2009, 15:35:03)
import math
import itertools
values = [ 1, 2, 3 ]
f = list( lambda x=i : x for i in range( 10 ) )
n = int( math.ceil( len(f)/float( len(values) ) ) )
for ff, dd in zip( f, itertools.chain(*zip( *n*[values] )) ):
.... print "Function %d applied to data %d." % ( ff(dd), dd )
....
Function 1 applied to data 1.
Function 1 applied to data 1.
Function 1 applied to data 1.
Function 1 applied to data 1.
Function 2 applied to data 2.
Function 2 applied to data 2.
Function 2 applied to data 2.
Function 2 applied to data 2.
Function 3 applied to data 3.
Function 3 applied to data 3.
 
W

Wolfram Hinderer

Hi,

I couldn't figure out a better description for the Subject line, but
anyway, I have the following:

_num_frames = 32
_frames = range(0, _num_frames) # This is a list of actual objects,
I'm just pseudocoding here.
_values = [0, 1, 2, 3, 4]

I want to call a function of _frames for each frame with a _values
argument, but in a way to "spread out" the actual values.

I would want something similar to the following to be called:

_frames[0].func(_values[0])
_frames[1].func(_values[0])
_frames[2].func(_values[0])
_frames[3].func(_values[0])
_frames[4].func(_values[1])
_frames[5].func(_values[1])
_frames[6].func(_values[1])
_frames[7].func(_values[1])
_frames[8].func(_values[2])
...etc...

Both the _values list and _frames list can be of variable and uneven
size, which is what is giving me the problems. I'm using Python 2.6.

I've tried the following workaround, but it often gives me inaccurate
results (due to integer division), so I had to add a safety check:

num_frames = 32
values = [0, 1, 2, 3, 4]
offset_step = num_frames / len(values)
    for index in xrange(0, num_frames):
        offset = index / offset_step
        if offset > offset_values[-1]:
            offset = offset_values[-1]
        frames[index].func(values[offset])

There has to be a better way to do this. I'd appreciate any help.
Cheers!

Python 3.1:.... num_funcs = len(funcs)
.... num_values = len(values)
.... for i, func in enumerate(funcs):
.... func(values[(i * num_values) // num_funcs])
apply_spreaded([print] * 8, range(5))
0
0
1
1
2
3
3
4
 
J

John Posner

Hi,

I couldn't figure out a better description for the Subject line, but
anyway, I have the following:

_num_frames = 32
_frames = range(0, _num_frames) # This is a list of actual objects,
I'm just pseudocoding here.
_values = [0, 1, 2, 3, 4]

I want to call a function of _frames for each frame with a _values
argument, but in a way to "spread out" the actual values.

I would want something similar to the following to be called:

_frames[0].func(_values[0])
_frames[1].func(_values[0])
_frames[2].func(_values[0])
_frames[3].func(_values[0])
_frames[4].func(_values[1])
_frames[5].func(_values[1])
_frames[6].func(_values[1])
_frames[7].func(_values[1])
_frames[8].func(_values[2])
...etc...

The lines above show that you are using two different series of index
values. Each function call (more properly, "method call") has the form:

frames[INDEX_FROM_FIRST_SERIES].func(INDEX_FROM_SECOND_SERIES)

(I've dropped the underscores in the names, for simplicity.) You're
getting hung up trying to keep the two series of index values in sync.
But you don't really need to. More below ...
Both the _values list and _frames list can be of variable and uneven
size, which is what is giving me the problems. I'm using Python 2.6.

I've tried the following workaround, but it often gives me inaccurate
results (due to integer division), so I had to add a safety check:

num_frames = 32
values = [0, 1, 2, 3, 4]
offset_step = num_frames / len(values)
for index in xrange(0, num_frames):
offset = index / offset_step
if offset> offset_values[-1]:
offset = offset_values[-1]
frames[index].func(values[offset])

There has to be a better way to do this. I'd appreciate any help.
Cheers!

As you've shown above, a "for" loop takes care of the first series of
index values:

for index in xrange(num_frames): # "0" arg unnecessary
frames[index].func(INDEX_FROM_SECOND_SERIES)

The second series of index values needs to look like this:

0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3 ...

The trick is not to worry about matching the second series to the first
series. Instead, create an "infinite" second series using a Python
generator, and use as many of its values as you need. Don't worry about
the unused values, because the series isn't *really* infinite. :)

Here's an easy way to create the generator

import itertools
second_series_gen = (i/4 for i in itertools.count())

Now, every time you need another number from this series, use its next()
method. So the above code becomes:

for index in xrange(num_frames):
frames[index].func(second_series_gen.next())

-John
 
P

Peter Otten

Andrej said:
Hi,

I couldn't figure out a better description for the Subject line, but
anyway, I have the following:

_num_frames = 32
_frames = range(0, _num_frames) # This is a list of actual objects,
I'm just pseudocoding here.
_values = [0, 1, 2, 3, 4]

I want to call a function of _frames for each frame with a _values
argument, but in a way to "spread out" the actual values.

I would want something similar to the following to be called:

_frames[0].func(_values[0])
_frames[1].func(_values[0])
_frames[2].func(_values[0])
_frames[3].func(_values[0])
_frames[4].func(_values[1])
_frames[5].func(_values[1])
_frames[6].func(_values[1])
_frames[7].func(_values[1])
_frames[8].func(_values[2])
...etc...

Both the _values list and _frames list can be of variable and uneven
size, which is what is giving me the problems. I'm using Python 2.6.

I've tried the following workaround, but it often gives me inaccurate
results (due to integer division), so I had to add a safety check:

num_frames = 32
values = [0, 1, 2, 3, 4]
offset_step = num_frames / len(values)
for index in xrange(0, num_frames):
offset = index / offset_step
if offset > offset_values[-1]:
offset = offset_values[-1]
frames[index].func(values[offset])

There has to be a better way to do this. I'd appreciate any help.
Cheers!

I tried to apply

http://en.wikipedia.org/wiki/Bresenham's_line_algorithm

on the problem:

def bresenham(xitems, yitems):
x1 = len(xitems)
y1 = len(yitems)

assert y1 <= x1
assert x1 > 0

deltax = x1-1
deltay = y1-1
error = deltax // 2

yitems = iter(yitems)
y = next(yitems)

for x in xitems:
yield x, y
error -= deltay
if error < 0:
y = next(yitems)
error += deltax

if __name__ == "__main__":
def make_f(i):
def f(v):
return "%d --> %s" % (i, v)
return f
functions = [make_f(i) for i in range(11)]
values = ["b%s" % k for k in range(5)]
for f, v in bresenham(functions, values):
print f(v)

The implementation is derived from the code on the wikipedia page and
untested.

Peter
 
A

Andrej Mitrovic

I couldn't figure out a better description for the Subject line, but
anyway, I have the following:
_num_frames = 32
_frames = range(0, _num_frames) # This is a list of actual objects,
I'm just pseudocoding here.
_values = [0, 1, 2, 3, 4]
I want to call a function of _frames for each frame with a _values
argument, but in a way to "spread out" the actual values.
I would want something similar to the following to be called:
_frames[0].func(_values[0])
_frames[1].func(_values[0])
_frames[2].func(_values[0])
_frames[3].func(_values[0])
_frames[4].func(_values[1])
_frames[5].func(_values[1])
_frames[6].func(_values[1])
_frames[7].func(_values[1])
_frames[8].func(_values[2])
...etc...

The lines above show that you are using two different series of index
values. Each function call (more properly, "method call") has the form:

   frames[INDEX_FROM_FIRST_SERIES].func(INDEX_FROM_SECOND_SERIES)

(I've dropped the underscores in the names, for simplicity.) You're
getting hung up trying to keep the two series of index values in sync.
But you don't really need to. More below ...




Both the _values list and _frames list can be of variable and uneven
size, which is what is giving me the problems. I'm using Python 2.6.
I've tried the following workaround, but it often gives me inaccurate
results (due to integer division), so I had to add a safety check:
num_frames = 32
values = [0, 1, 2, 3, 4]
offset_step = num_frames / len(values)
     for index in xrange(0, num_frames):
         offset = index / offset_step
         if offset>  offset_values[-1]:
             offset = offset_values[-1]
         frames[index].func(values[offset])
There has to be a better way to do this. I'd appreciate any help.
Cheers!

As you've shown above, a "for" loop takes care of the first series of
index values:

   for index in xrange(num_frames):       # "0" arg unnecessary
       frames[index].func(INDEX_FROM_SECOND_SERIES)

The second series of index values needs to look like this:

   0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3 ...

The trick is not to worry about matching the second series to the first
series. Instead, create an "infinite" second series using a Python
generator, and use as many of its values as you need. Don't worry about
the unused values, because the series isn't *really* infinite. :)

Here's an easy way to create the generator

   import itertools
   second_series_gen = (i/4 for i in itertools.count())

Now, every time you need another number from this series, use its next()
method. So the above code becomes:

   for index in xrange(num_frames):
       frames[index].func(second_series_gen.next())

-John

That's a cool trick, but maybe I wasn't specific enough. The values
series are the range of values that the frames.func() function should
use, it should not overflow, and I would want the function to use as
evenly distributed number of values as possible from the first series.
The "0000,1111" was just an example. Let me see if I can be more
specific:

values = [2, 3, 4]
frames = [obj1, obj2, obj3, obj4, obj5, obj6]

And the calls:

frames[0].func(values[0]) # func.(values[2])
frames[1].func(values[0]) # func.(values[2])
frames[2].func(values[1]) # func.(values[3])
frames[3].func(values[1]) # func.(values[3])
frames[4].func(values[2]) # func.(values[4])
frames[5].func(values[2]) # func.(values[4])


However the values list might have an uneven number of items. I would
like to make it as evenly distributed as possible, e.g.:

values = [-2, -1, 0]
frames = [obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8]

frames[0].func(values[0]) # func.(values[-2])
frames[1].func(values[0]) # func.(values[-2])
frames[2].func(values[1]) # func.(values[-2])
frames[3].func(values[1]) # func.(values[-1])
frames[4].func(values[1]) # func.(values[-1])
frames[5].func(values[2]) # func.(values[-1])
frames[6].func(values[2]) # func.(values[0])
frames[7].func(values[2]) # func.(values[0])


I'll be even more specific. I have a Minimum and Maximum value that
the user enters. The frame.func() function is a "translate" function,
it basically moves a frame in the application in one direction or
another depending on the argument value. So frame[0].func(2) would
move the frame[0] 2 pixels to the right. So what I want is the
function to create a smooth transition of all the frames from the
Minimum to the Maximum value. If minimum was 0, and maximum was 10,
I'd want the first frame moved 0 pixels (it stays in place), the last
frame to move 10 pixels, and the frames between are gradually moved
from 1 pixels to 9 pixels relative from their positions.

Perhaps I'm just overcomplicating. I'll have a look at some drawing
apps and see how they've implemented drawing straight lines under an
angle, I guess that could be called a gradual change of values.

Thanks for all the suggestions everyone, I'll have a look at the rest
shortly.
 
D

Dave Angel

Andrej said:
On 2/17/2010 1:10 PM, Andrej Mitrovic wrote:

<snip>

However the values list might have an uneven number of items. I would
like to make it as evenly distributed as possible, e.g.:

values =-2, -1, 0]
frames =obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8]

frames[0].func(values[0]) # func.(values[-2])
frames[1].func(values[0]) # func.(values[-2])
frames[2].func(values[1]) # func.(values[-2])
frames[3].func(values[1]) # func.(values[-1])
frames[4].func(values[1]) # func.(values[-1])
frames[5].func(values[2]) # func.(values[-1])
frames[6].func(values[2]) # func.(values[0])
frames[7].func(values[2]) # func.(values[0])


I'll be even more specific. I have a Minimum and Maximum value that
the user enters. The frame.func() function is a "translate" function,
it basically moves a frame in the application in one direction or
another depending on the argument value. So frame[0].func(2) would
move the frame[0] 2 pixels to the right. So what I want is the
function to create a smooth transition of all the frames from the
Minimum to the Maximum value. If minimum was 0, and maximum was 10,
I'd want the first frame moved 0 pixels (it stays in place), the last
frame to move 10 pixels, and the frames between are gradually moved
from 1 pixels to 9 pixels relative from their positions.

Perhaps I'm just overcomplicating. I'll have a look at some drawing
apps and see how they've implemented drawing straight lines under an
angle, I guess that could be called a gradual change of values.

Thanks for all the suggestions everyone, I'll have a look at the rest
shortly.
I think you're overcomplicating. If you have 27 frames, and you want
frame 0 to move 0 pixels, and frame 27 to move 10 pixels, then you want
to move frame by i*10/27. And since you do the multiply first, the
fact that Python 2.x division gives you integers isn't a problem.

There are fancier methods for drawing lines (bresenham for example), but
the main purpose of them is to to avoid multiply and divide, as well as
floats. But in Python, an integer multiply is just as fast as an add or
subtract, so there's no point.

DaveA
 
A

Andrej Mitrovic

However the values list might have an uneven number of items. I would
like to make it as evenly distributed as possible, e.g.:
values =-2, -1, 0]
frames =obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8]
frames[0].func(values[0])  # func.(values[-2])
frames[1].func(values[0])  # func.(values[-2])
frames[2].func(values[1])  # func.(values[-2])
frames[3].func(values[1])  # func.(values[-1])
frames[4].func(values[1])  # func.(values[-1])
frames[5].func(values[2])  # func.(values[-1])
frames[6].func(values[2])  # func.(values[0])
frames[7].func(values[2])  # func.(values[0])
I'll be even more specific. I have a Minimum and Maximum value that
the user enters. The frame.func() function is a "translate" function,
it basically moves a frame in the application in one direction or
another depending on the argument value. So frame[0].func(2) would
move the frame[0] 2 pixels to the right. So what I want is the
function to create a smooth transition of all the frames from the
Minimum to the Maximum value. If minimum was 0, and maximum was 10,
I'd want the first frame moved 0 pixels (it stays in place), the last
frame to move 10 pixels, and the frames between are gradually moved
from 1 pixels to 9 pixels relative from their positions.
Perhaps I'm just overcomplicating. I'll have a look at some drawing
apps and see how they've implemented drawing straight lines under an
angle, I guess that could be called a gradual change of values.
Thanks for all the suggestions everyone, I'll have a look at the rest
shortly.

I think you're overcomplicating.  If you have 27 frames, and you want
frame 0 to move 0 pixels, and frame 27 to move 10 pixels, then you want
to move frame by i*10/27.  And since you do the multiply first, the
fact that Python 2.x division gives you integers isn't a problem.

There are fancier methods for drawing lines (bresenham for example), but
the main purpose of them is to to avoid multiply and divide, as well as
floats.  But in Python, an integer multiply is just as fast as an add or
subtract, so there's no point.

DaveA


Doh! Such a simple solution, just what I was looking for. Thanks!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,190
Latest member
ClayE7480

Latest Threads

Top