Alonzo Quijote | 4 Aug 2012 08:58
Picon

Recursive assignment in nested lists

Is there a way to define a function which takes
   a list (of lists),
   a position specified by a list of integers [i0,i1,...,in], and
   a value
and returns the result of setting 
    list[i0][i1]...[in]=value

The following function works for positions up to length 3 only.
Is it possible to write a general function that does this?

def setValueAtPosition(list,pos,value):
    if len(pos)==1:
        list[pos[0]]=value
    elif len(pos)==2:
        list[pos[0]][pos[1]]=value
    elif len(pos)==3:
        list[pos[0]][pos[1]][pos[2]]=value
    return list

For example
>>> aa=[1,2,[3,4]]

>>> setValueAtPosition(aa,[2,0],5)
[1, 2, [5, 4]]

>>> aa
[1, 2, [5, 4]]

_______________________________________________
Tutor maillist  -  Tutor <at> python.org
(Continue reading)

Puneeth Chaganti | 4 Aug 2012 09:20
Picon
Gravatar

Re: Recursive assignment in nested lists

On Sat, Aug 4, 2012 at 12:28 PM, Alonzo Quijote
<alonzo.quijote <at> gmail.com> wrote:
> Is there a way to define a function which takes
>    a list (of lists),
>    a position specified by a list of integers [i0,i1,...,in], and
>    a value
> and returns the result of setting
>     list[i0][i1]...[in]=value
>
> The following function works for positions up to length 3 only.
> Is it possible to write a general function that does this?
>
> def setValueAtPosition(list,pos,value):
>     if len(pos)==1:
>         list[pos[0]]=value
>     elif len(pos)==2:
>         list[pos[0]][pos[1]]=value
>     elif len(pos)==3:
>         list[pos[0]][pos[1]][pos[2]]=value
>     return list

Something like this, should work :

def setValueAtPosition(my_list, pos, value):
    sub_list = my_list
    for i in pos[:-1]:
        sub_list = sub_list[i]
    sub_list[pos[-1]] = value
    return my_list

(Continue reading)

Steven D'Aprano | 4 Aug 2012 09:27

Re: Recursive assignment in nested lists

On 04/08/12 16:58, Alonzo Quijote wrote:
> Is there a way to define a function which takes
>     a list (of lists),
>     a position specified by a list of integers [i0,i1,...,in], and
>     a value
> and returns the result of setting
>      list[i0][i1]...[in]=value

Yes it is possible, but if you need this, you should strongly consider 
rearranging your data so it is easier to work with.

But, for what it's worth, try this:

def setValueAtPosition(list, pos, value):
     tmp = list
     for i in pos[:-1]:
         tmp = tmp[i]
     tmp[pos[-1]] = value

There's no need to return the list argument, because it changes it in-place.

And here is your example:

py> aa=[1, 2, [3, 4]]
py> setValueAtPosition(aa, [2, 0], 5)
py> aa
[1, 2, [5, 4]]

And a more complicated example:

(Continue reading)

Peter Otten | 4 Aug 2012 09:43
Picon

Re: Recursive assignment in nested lists

Alonzo Quijote wrote:

> Is there a way to define a function which takes
>    a list (of lists),
>    a position specified by a list of integers [i0,i1,...,in], and
>    a value
> and returns the result of setting
>     list[i0][i1]...[in]=value
> 
> The following function works for positions up to length 3 only.
> Is it possible to write a general function that does this?
> 
> def setValueAtPosition(list,pos,value):
>     if len(pos)==1:
>         list[pos[0]]=value
>     elif len(pos)==2:
>         list[pos[0]][pos[1]]=value
>     elif len(pos)==3:
>         list[pos[0]][pos[1]][pos[2]]=value
>     return list
> 
> For example
>>>> aa=[1,2,[3,4]]
> 
>>>> setValueAtPosition(aa,[2,0],5)
> [1, 2, [5, 4]]
> 
>>>> aa
> [1, 2, [5, 4]]

(Continue reading)

Alonzo Quijote | 4 Aug 2012 21:44
Picon

Re: Recursive assignment in nested lists

Thanks for all the help with this. I have 2 very quick follow-up questions:
---
1. Several responses proposed code like this:

def setValueAtPosition(list, pos, value):
   tmp = list
   for i in pos[:-1]:
       tmp = tmp[i]
   tmp[pos[-1]] = value

There must be a good reason that the responders use a tmp variable like this?
But I notice that the same effects can be obtained with:

def setValueAtPosition2(list, pos, value):
     for i in pos[:-1]:
         list = list[i]
     list[pos[-1]] = value

Is there something wrong with this latter approach?
---
2. Another response observes that the function can be defined recursively like this:

def setValueAtPosition3(list, pos, value):
    if len(pos) == 1:
        list[pos[0]] = value
    else:
        inner_list = list[pos[0]]
        new_pos = pos[1:]
        setValueAtPosition3(inner_list, new_pos, value)

(Continue reading)

Alan Gauld | 4 Aug 2012 22:48

Re: Recursive assignment in nested lists

On 04/08/12 20:44, Alonzo Quijote wrote:

> There must be a good reason that the responders use a tmp variable like this?
> But I notice that the same effects can be obtained with:
>
> def setValueAtPosition2(list, pos, value):
>       for i in pos[:-1]:
>           list = list[i]
>       list[pos[-1]] = value
>
> Is there something wrong with this latter approach?

Not for the specific case but the problem comes because you lost the 
reference to the original list which is usually a bad idea, especially 
if you decide you need to do anything with it.

> 2. Another response observes that the function can be defined recursively like this:
> Are the non-recursive solutions better?

Define "better".
Recursive functions in Python have a limit on the recursion depth so for 
a very long list it will break. Recursion also tends to use more memory.

Use recursion where you have shallow data structures or very complex 
structures which are themselves recursive - then rewrite it without 
recursion, but only if necessary due to the above limitations.

--

-- 
Alan G
Author of the Learn to Program web site
(Continue reading)

Asokan Pichai | 4 Aug 2012 09:44
Favicon

Re: Recursive assignment in nested lists

On Sat, Aug 4, 2012 at 12:28 PM, Alonzo Quijote
<alonzo.quijote <at> gmail.com> wrote:
> Is there a way to define a function which takes
>    a list (of lists),
>    a position specified by a list of integers [i0,i1,...,in], and
>    a value
> and returns the result of setting
>     list[i0][i1]...[in]=value
>
> The following function works for positions up to length 3 only.
> Is it possible to write a general function that does this?
>
> def setValueAtPosition(list,pos,value):
>     if len(pos)==1:
>         list[pos[0]]=value
>     elif len(pos)==2:
>         list[pos[0]][pos[1]]=value
>     elif len(pos)==3:
>         list[pos[0]][pos[1]][pos[2]]=value
>     return list
>
> For example
>>>> aa=[1,2,[3,4]]
>
>>>> setValueAtPosition(aa,[2,0],5)
> [1, 2, [5, 4]]
>
>>>> aa
> [1, 2, [5, 4]]
>
(Continue reading)


Gmane