# How to use pattern matching to apply a function to specific elements of a matrix

I have a 3x3 matrix

testweightedgraph = {{{}, {p, q, pq, pq}, {}}, {{p, q, pq,
pq}, {q}, {}}, {{}, {}, {}}};


whose elements are (possibly empty) lists.

I would like to apply the pure function

1 - Apply[Times, 1 - #] &


to every nonempty element of the matrix, leaving the empty elements exactly as they are. The result I want is this:

{{{}, {1 - (1 - p) (1 - pq)^2 (1 - q)}, {}}, {{1 - (1 - p) (1 -
pq)^2 (1 - q)}, {q}, {}}, {{}, {}, {}}}


If I use

Map[{1 - Apply[Times, 1 - #]} &, testweightedgraph, {2}]


then I get

{{{0}, {1 - (1 - p) (1 - pq)^2 (1 - q)}, {0}}, {{1 - (1 - p) (1 -
pq)^2 (1 - q)}, {q}, {0}}, {{0}, {0}, {0}}}


which is perfect, except that all instances of {0} should be replaced by {}.

Rather than patching the result, by somehow replacing {0}s by {}s, I would like to get it right in the first place.

One option seems to be to use Position and feed its results to MapAt. This has two disadvantages for me: 1) Perhaps Position needs to be told exactly what to look for, and cannot be asked to look for elements satisfying a pattern (such as, in this case "not being the empty list"). 2) If we are going to have to use pattern matching anyway, then isn't there a more direct way to do it, without using Position or MapAt ?

I have studied the tutorials on Pattern Matching but I confess I find it very hard to understand.

Design a function that ignores empty lists:

f[{}] = {};
f[{a__}] := {1 - Times @@ (1 - {a})}
Map[f, testweightedgraph, {2}]

{
{{}, {1 - (1 - p) (1 - pq)^2 (1 - q)}, {}},
{{1 - (1 - p) (1 - pq)^2 (1 - q)}, {q}, {}},
{{}, {}, {}}
}

• @Simon note the minor correction I just added (f[{a__}] rather than f[a__]). It might be better suited to handling certain corner cases. Oct 21, 2015 at 9:39
• Thank you ! Yes when I tried your first set of code the nonempty lists were simply wrapped in {}, without the subtraction, multiplication and subtraction being performed. Your new code works perfectly for me. This serves two purposes: Solving my problem and also giving me a good example from which to start understanding pattern matching. Very many thanks ! Oct 21, 2015 at 9:41

This is the sort of thing If[] was meant for:

Map[If[# =!= {}, 1 - Apply[Times, 1 - #], #] &, testweightedgraph, {2}]

• That is also a very nice answer, thank you J. M. I like the piecewise definition of LLIAMnYP's answer, and I like that J. M.'s doesn't define a named function. P.S. J. M. since I want my matrix elements to be lists, I have added some curly braces to your code: Map[If[# =!= {}, {1 - Apply[Times, 1 - #]}, #] &, testweightedgraph, {2}] Oct 21, 2015 at 12:18

With respect to your list of disadvantages about using Position to resolve the problem

Perhaps Position needs to be told exactly what to look for, and cannot be asked to look for elements satisfying a pattern (such as, in this case "not being the empty list")

I think that you can use a general pattern to extract non empty lists

testweightedgraph = {{{}, {p, q, pq, pq}, {}}, {{p, q, pq,
pq}, {q}, {}}, {{}, {}, {}}}

Position[testweightedgraph, {x__}, {2}]
(* {{1, 2}, {2, 1}, {2, 2}} *)


and then as you suggested use MapAt

MapAt[{1 - Apply[Times, 1 - #]} &, testweightedgraph,
Position[testweightedgraph, {a__}, {2}]]


• You are absolutely right, Jack - thank you very much for answering ! It's so nice to have many different ways of doing the same thing. I can imagine each of these might be preferable to the others, in the right situation. Oct 22, 2015 at 17:02