"for" cycle with assigning index

D

dmitrey

Hi all,
could you inform me how to do it properly?

I have the cycle

for i in xrange(len(Funcs2)): # Funcs2 is Python dict
Funcs.append(lambda *args, **kwargs: (Funcs2(*args, **kwargs)
[IndDict[left_arr_indexes]]))

So, all the Funcs are initialized with i = last index = len(Funcs2)

When I involve

for i in xrange(len(Funcs2)):
Funcs.append(lambda i=i,*args, **kwargs: (Funcs2(*args,
**kwargs)[IndDict[left_arr_indexes]]))

I get "list indices must be integers, not dict" (and i is equal to
Python dictionary, that is Funcs2)

So, how to do it correctly?
Thank you in advance, D.
 
C

Carl Banks

Hi all,
could you inform me how to do it properly?

I have the cycle

for i in xrange(len(Funcs2)): # Funcs2 is Python dict
     Funcs.append(lambda *args, **kwargs: (Funcs2(*args, **kwargs)
[IndDict[left_arr_indexes]]))

So, all the Funcs are initialized with i = last index = len(Funcs2)

When I involve

for i in xrange(len(Funcs2)):
     Funcs.append(lambda i=i,*args, **kwargs: (Funcs2(*args,
**kwargs)[IndDict[left_arr_indexes]]))

I get "list indices must be integers, not dict" (and i is equal to
Python dictionary, that is Funcs2)

So, how to do it correctly?
Thank you in advance, D.



Define a helper function to do it:

def create_funcs_caller(i):
def func(*args,**kwargs):
return(Funcs2(*args,**kwargs)[IndDict[left_arr_indexes
]]))
retirm func

for i in xrange(len(Funcs2)):
Funcs.append(create_funcs_caller(i))


(I prefer to do it this way in any case; never liked the keyword
argument hack way of doing it.)


Carl Banks
 
P

Paul Rubin

Carl Banks said:
def create_funcs_caller(i):
def func(*args,**kwargs):
return(Funcs2(*args,**kwargs)[IndDict[left_arr_indexes]])
retirm func

for i in xrange(len(Funcs2)):
Funcs.append(create_funcs_caller(i))


I prefer to get rid of the index variable:

def create_funcs_caller(f,ix):
return lambda *args, **kw: f(*args,**kw)[ix]

Funcs = list(create_funcs_caller(f,ix)
for f,ix in zip(Funcs2, left_arr_indexes))

Or in point-free style:

from itertools import starmap

Funcs = starmap(create_funcs_caller, zip(Funcs2,left_arr_indexes))
 
D

Dennis Lee Bieber

for i in xrange(len(Funcs2)): # Funcs2 is Python dict
Funcs.append(lambda *args, **kwargs: (Funcs2(*args, **kwargs)
[IndDict[left_arr_indexes]]))

So, all the Funcs are initialized with i = last index = len(Funcs2)

When I involve

for i in xrange(len(Funcs2)):
Funcs.append(lambda i=i,*args, **kwargs: (Funcs2(*args,
**kwargs)[IndDict[left_arr_indexes]]))

I get "list indices must be integers, not dict" (and i is equal to
Python dictionary, that is Funcs2)

"i" is NOT "equal to ... dictionary"

"i" is an index from 0..(len-1) of the number of elements IN the
dictionary. You state that Funcs2 is a dictionary, therefore

Funcs2 will only work if the keys of the dictionary happen to be
sequential integers beginning with 0... And if they ARE sequential
integers, why are you using a dictionary and not a list?

And without some explanation of IndDict, the rest is an overly
confused mess to me... It looks like you are trying to create a list of
anonymous functions which are to call some element of Funcs2 AND then
access an element of what has to be a returned container type accessed
by a three layer indirection.

Presuming Funcs2 really is such a dictionary
{ 0 : f1, 1 : f2, ... }
and not a list
[ f1, f2, ... ]
the first thing I'd consider is using
for k, v in Funcs2.items():
(where k is the key -- integer, and v is the function itself) and
replace
... Funcs2 ...
with the simple
... v ...

If Funcs2 is set up as a list, instead
for i, f in enumerate(Funcs2):
(i is the index, f is the function) and use
... f ...
 
D

Dennis Lee Bieber

On Sat, 15 Aug 2009 13:22:08 -0700, Dennis Lee Bieber
<[email protected]> declaimed the following in
gmane.comp.python.general:

Okay -- my lack of experience with lambda shows... forgot to guard
the intermediates...
for i in xrange(len(Funcs2)):
Funcs.append(lambda i=i,*args, **kwargs: (Funcs2(*args,
**kwargs)[IndDict[left_arr_indexes]]))

I get "list indices must be integers, not dict" (and i is equal to
Python dictionary, that is Funcs2)


So... with the following assumptions (and ignoring all the other
respondents <G>)...

1) Funcs2 IS a dictionary keyed by sequential integers starting at 0
2) Order in Funcs matters; that is, the first element of the list must
align with the element of the dictionary having key "0"
3) IndDict and left_arr_indexes DO NOT CHANGE CONTENT after the loop
runs
4) left_arr_indexes is at least as long as Funcs2

assert (min(Funcs2.keys()) == 0
and
max(Funcs2.keys()) == (len(Funcs2) - 1)) #1
assert len(left_arr_indexes) >= len(Funcs2) #4

Funcs = [None] * len(Funcs2) #2a
for ki, fv in Funcs2.items(): #ki->key as index; fv->function value
ritmp = IndDict[left_arr_indexes[ki]] #3
Funcs[ki] = (lambda ri=ritmp, fn=fv, *args, **kwargs:
(fn(*args, **kwargs)[ri]) #2b


ri and fn used to protect the intermediates, ritmp and fv, from changes

2a is needed as the order of .items() is undefined, so .append() can not
be used. This presets the result list size permitting direct indexing
(2b) to fill slots in order.

#1 can still fail itself if a key is NOT an integer (what is the min()
of 0 and "a")

I still don't know if IndDict is really a list or a dictionary, nor
what left_array_indexes contains (by name, it is a list of values to
index into another list -- but could be a list of keys to access a
dictionary)

And I'll reiterate: if you are using dictionaries in which the keys
are sequential integers starting at 0... Replace them with simple
lists...
 
D

dmitrey

Thanks all, especially Dennis for your detailed answer.
left_arr_indexes is list of nonnegative integers, eg [0,0,0,1,1,4]
IndDict is a dict like {0: [1,2], 3: [0,1], 10:[0,2,3]}, so that's why
I don't use python list instead.
The code is taken from OpenOpt framework that I develop. Currently I
have implemented another workaround but the solution you proposed can
be used in other parts of code.
Regards, D.

@ix.netcom.com> declaimed the following in
gmane.comp.python.general:

        Okay -- my lack of experience with lambda shows... forgot to guard
the intermediates...
for i in xrange(len(Funcs2)):
     Funcs.append(lambda i=i,*args, **kwargs: (Funcs2(*args,
**kwargs)[IndDict[left_arr_indexes]]))
I get "list indices must be integers, not dict" (and i is equal to
Python dictionary, that is Funcs2)


        So... with the following assumptions (and ignoring all the other
respondents <G>)...

1)      Funcs2 IS a dictionary keyed by sequential integers starting at 0
2)      Order in Funcs matters; that is, the first element of the list must
align with the element of the dictionary having key "0"
3)      IndDict and left_arr_indexes DO NOT CHANGE CONTENT after the loop
runs
4)      left_arr_indexes is at least as long as Funcs2

assert (min(Funcs2.keys()) == 0
                        and
                max(Funcs2.keys()) == (len(Funcs2) - 1))        #1
assert len(left_arr_indexes) >= len(Funcs2)          #4

Funcs = [None] * len(Funcs2)                                            #2a
for ki, fv in Funcs2.items():   #ki->key as index; fv->function value
        ritmp = IndDict[left_arr_indexes[ki]]                           #3
        Funcs[ki] = (lambda ri=ritmp, fn=fv, *args, **kwargs:
                                        (fn(*args, **kwargs)[ri])                       #2b

ri and fn used to protect the intermediates, ritmp and fv, from changes

2a is needed as the order of .items() is undefined, so .append() can not
be used. This presets the result list size permitting direct indexing
(2b) to fill slots in order.

#1 can still fail itself if a key is NOT an integer (what is the min()
of 0 and "a")

        I still don't know if IndDict is really a list or a dictionary, nor
what left_array_indexes contains (by name, it is a list of values to
index into another list -- but could be a list of keys to access a
dictionary)

        And I'll reiterate: if you are using dictionaries in which the keys
are sequential integers starting at 0... Replace them with simple
lists...
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top