# Setting parts of a list

Suppose I have list

a = Range[10]


{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

in which I want to set some elements to be a list

a[[4 ;; 7]] = {1, 2, 3};


{1, 2, 3, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, 8, 9, 10}

Which is fine and dandy unless my part span is the same length as my list:

a[[4 ;; 6]] = {1, 2, 3};


{1, 2, 3, 1, 2, 3, 7, 8, 9, 10}

How can I force the assignment to behave consistently? In my case, I always want the first behaviour. But conceivably someone might always want the second behaviour with errors if the lengths don't match.

-

(a[[#]] = {1, 2, 3}) & /@ Range[4, 6];


You get:

In[1]:= a

Out[1]= {1, 2, 3, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, 7, 8, 9, 10}


A convenient thing to remember is that if your elements are not sequential it is still easy to set up:

(a[[#]] = {1, 2, 3}) & /@ {1, 3, 10};

In[2]:= a

Out[2]= {{1, 2, 3}, 2, {1, 2, 3}, 4, 5, 6, 7, 8, 9, {1, 2, 3}}

-
+1 for keeping in-place modification – Mr.Wizard Mar 23 '12 at 0:05
but this doesn't automate keeping the behaviour of Set consistent as the question asks (although it does do what is desired). then again neither does any other answer, nor anything I can come up with... – acl Mar 23 '12 at 1:09
The in-place modification aspect of this answer works best for my actual problem. But as acl says, the more general question remains. – wxffles Mar 23 '12 at 3:12

Perhaps

a = Range[10]

a[[4 ;; 6]] = Sequence@{1, 2, 3};


Returns

{1, 2, 3, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, 7, 8, 9, 10}


However, as Mr.Wizard noted in a comment, this is a LIIIEEE. If you do Information[a] you see that the Sequence is actually being saved. I find this weird, but anyway, can be solved with an extra

a=a


Also, forcing the lhs and rhs lists to be a different size should work a[[{4,5,6,4}]]={1, 2, 3}

-
This actually doesn't work quite seamlessly. Try Information[a]. – Mr.Wizard Mar 22 '12 at 23:47
Oooooops, thanks – Rojo Mar 22 '12 at 23:48
@Mr.Wizard, it's weird that essentially with Set this returns a delayed assignment. Wasn't expecting that, good catch – Rojo Mar 22 '12 at 23:52
take another look. If it doesn't work, delete again. :^) – Mr.Wizard Mar 22 '12 at 23:53
+1 as this is the only answer in the spirit of the question (or anyway what I took to be the spirit of the question) – acl Mar 23 '12 at 1:09

Here's a way that's in two-steps, but works nevertheless:

a[[4 ;; 6]] = \[FormalF][1, 2, 3];
a = a /. \[FormalF] -> List
Out[1]= {1, 2, 3, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, 7, 8, 9, 10}


Here's another solution using MapAt, but this loses the convenience of indexing with Span.

a = MapAt[{1, 2, 3} &, a, Transpose[{Range[4, 6]}]]
Out[2]= {1, 2, 3, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, 7, 8, 9, 10}


But the standard way to replace elements in a safe manner and for cases where you want different replacements for each, is to use ReplacePart as:

a = ReplacePart[a, Transpose[{Range[4, 6]}] -> {1, 2, 3}]
Out[3]= {1, 2, 3, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, 7, 8, 9, 10}

-

After reading the answers, this is one way more to do it (maybe too simple):

a[[4 ;; 6]] = ConstantArray[{1, 2, 3}, 3];


Thinking in it, you can do your own simple Set:

Attributes[simpleSet] = {HoldFirst};
simpleSet[lhs_, rhs_] :=
With[{newrhs = ConstantArray[rhs, Length[lhs]]}, lhs = newrhs];


And use it as Set:

simpleSet[a[[4 ;; 6]], {1, 2, 3}];

{{1, 2, 3}, {1, 2, 3}, {1, 2, 3}}


And it returns the same as Set returns: what it is assigned.

a

{1, 2, 3, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, 7, 8, 9, 10}

-