# Replace a value in a nested array

When I run the following,

red = {{{-4, 50}, {100, 136}}, {{-19, 1}, {35, 73}}, {{-24, 0}, {26, 63}}};
y = {{0.01497, 1}, {0.04304, 3}, {0.07111, 2}, {0.09918, 1}};
red=Interval@@@red;
If[#[[1]] <= 0.05, xii = #[[2]]; If[IntervalMemberQ[red[[xii]], 47], #[[1]] = 999.];] & /@ y;
y


y = {{999., 1}, {999., 3}, {0.07111, 2}, {0.09918, 1}}


I am getting an error:

 Set::setps:{0.01497,1} in the part assignment is not a symbol. >>


I know based on this that it is to do with passing name of the variable vs. value of the variable, but not sure how to fix it. I tried Insert[#, 999., 1] and ReplaceList[#, 1 -> 999.] without much success :(

-

Assuming I follow what you are doing I believe this may be the simplest correction:

red = {{{-4, 50}, {100, 136}}, {{-19, 1}, {35, 73}}, {{-24, 0}, {26, 63}}};
y = {{0.01497, 1}, {0.04304, 3}, {0.07111, 2}, {0.09918, 1}};
red = Interval @@@ red;

Do[
If[
y[[i, 1]] <= 0.05,
xii = y[[i, 2]]; If[IntervalMemberQ[red[[xii]], 47], y[[i, 1]] = 999.];
],
{i, Length@y}
]

y

{{999., 1}, {999., 3}, {0.07111, 2}, {0.09918, 1}}


However you may find that in-place modification of y is not beneficial; in that case consider something like this:

y = {{0.01497, 1}, {0.04304, 3}, {0.07111, 2}, {0.09918, 1}};

fn[{a_, b_}] /; a <= 0.05 && IntervalMemberQ[red[[b]], 47] := {999., b}

fn[else_] := else

fn /@ y

{{999., 1}, {999., 3}, {0.07111, 2}, {0.09918, 1}}

-
Pattern matching approach based 100% on @Mr.Wizard's answer: y /. {a_, b_} /; a <= 0.05 && IntervalMemberQ[red[[b]], 47] :> {999., b} – seismatica Aug 8 '14 at 6:54
@seismatica Very nice. Consider using Replace with a levelspec of {1} for optimum performance. In writing the answer above I was thinking about a function that could be mapped but freed from that I prefer your approach. :-) – Mr.Wizard Aug 8 '14 at 6:56
Thanks for the tip! Have to admit I'm rather spoilt by all the short notations of MMA that I'd just feel too lazy to use Replace with all those extra characters :p – seismatica Aug 8 '14 at 6:59
@seismatica It sounds like I have a disciple in the School of Terse! :D – Mr.Wizard Aug 8 '14 at 7:06

Attempt from question : Mutable and immutable approach mixed up (not working)

As Mr.Wizard pointed out, there is a mutable approach and an immutable approach. In the first case you modify y directly. In the second case the program returns a whole new vector, and you assign y the value of this vector.

In the question you mix the two approaches, because you use map[], which returns an expression, and at the same time you try to modify y directly. However, something goes wrong when you try to modify y.

#[[1]] refers to the value of y[[1]] and not to the variable y[[y]]

Mutable and immutable approach mixed up (working)

If you want to use a map (like you did with /@), than use MapIndexed.

Try MapIndexed[f, {a, b, c}] to understand how it works

{f[a, {1}], f[b, {2}], f[x, {3}]}


Now you can refere to y[[#2[[1]]

red = {{{-4, 50}, {100, 136}}, {{-19, 1}, {35, 73}}, {{-24, 0}, {26, 63}}};
y = {{0.01497, 1}, {0.04304, 3}, {0.07111, 2}, {0.09918, 1}};
red = Interval @@@ red;

MapIndexed[
If[#1[[1]] <= 0.05, xii = #1[[2]];
If[IntervalMemberQ[red[[xii]], 47], y[[#2[[1]], 1]] = 999.];
]&
, y];


Mutable aproach

Mr.Wizard used a Do loop, which does not return an expression.

Immutable approach

Map[
{ If[#[[1]] <= 0.05,
xii = #[[2]];
If[IntervalMemberQ[red[[xii]], 47], 999., #[[1]]];
, #[[1]]]
, #[[2]]
} &
, y]


This returns

{{999., 1}, {999., 3}, {0.07111, 2}, {0.09918, 1}}

-
I voted for this because it is clean, and I like that, but the reason I chose Do is that using Map (or MapIndexed) builds an output expression which pretty much defeats any use of in-place modification. IMHO either use Scan or Do for a mutable style or choose an immutable style and use Map` etc. – Mr.Wizard Aug 8 '14 at 6:11
@Mr.Wizard Thanks for this comment. Indeed you could rewrite this in immutable style. Now it mixes up two approaches. – sjdh Aug 8 '14 at 6:17