# Manipulating sparse array elements

Suppose I have two sparse arrays

L = SparseArray[{{1, 1} -> 1, {1, 5} -> 4, {5, 1} -> 1, {5, 5} ->
2, {10, 10} -> 2, {10, 14} -> 2, {10, 18} -> 1, {14, 10} ->
2, {14, 14} -> 2, {14, 18} -> 1, {18, 10} -> -1, {18, 14} ->
1, {18, 18} -> 1, {19, 19} ->
1, {19, 23} -> -1, {19, 27} -> -1, {23, 19} -> 1, {23, 23} ->
2, {23, 27} -> 1, {27, 19} -> 1, {27, 23} -> 1, {27, 27} -> 1}];


and

R = SparseArray[{{1, 1} -> -1, {1, 5} -> 3, {5, 1} -> 1, {5, 5} ->
2, {10, 10} -> 2, {10, 14} -> 2, {10, 18} -> 1, {14, 10} ->
2, {14, 14} -> 2, {14, 18} -> -1, {18, 10} -> -2, {18, 14} ->
4, {18, 18} -> 1, {19, 19} ->
1, {19, 23} -> -1, {19, 27} -> -3, {23, 19} -> 1, {23, 23} ->
2, {23, 27} -> 1, {27, 19} -> 1, {27, 23} -> 1, {27, 27} -> 1}];


My problem is to construct another sparse matrix whose entries are coming from the above matrices with some specific properties. (Well I just need to get the ArrayRules, obviously). For instance, I need to get the sparse matrix P whose nonzero entries are union of the positive entries entries of L and R, i.e. if any position of L (resp. R) has a positive entry, P should also have a positive entry. Now the union of the positions can be taken easily by

Union[Cases[ArrayRules[L, (r : (_ -> x_ /; Positive[x])) -> r], Cases[ArrayRules[R, (r : (_ -> x_ /; Positive[x])) -> r]]


But here is the problem. Notice that, the entry {1,5}->4 in the first list and {1,5}->3 in the second list (and sometimes the opposite). If such a situation (or say collision) happens, then the position {1,5} of the output sparse matrix should have the maximum of the all possible values (here 4). Is it possible to write it neatly? I also need to make a sparse matrix N, whose non zero entries are common nonzero entries of L and R, with the caveat that for a collision, as defined above, the corresponding entry is the minimum of all possible entries.

SortBy[Union[Cases[ArrayRules[L], (r : (_ -> x_ /; Positive[x])) -> r],
Cases[ArrayRules[R], (r : (_ -> x_ /; Positive[x])) -> r]], Last] // Reverse


This sorts the rules by value of element, reversing it puts larger elements with same index first, default behavior of SparseArray is to ignore later rules with same source.

Same idea sans the Reverse should serve the second part of your question.

BTW, if arrays are large, probably better to do this with masking, e.g.:

ar1 = Clip[array1, {0, Infinity}];

ar2 = Clip[array2, {0, Infinity}];

us = UnitStep[ar1 - ar2];

resultArray = mask*(us*ar1 + BitXor[1, us]*ar2);


gives the maximum result, same idea applies to minimum. Should be much faster on large cases.

N.B.: I interpret your query as only those entries where both have a positive value. If not the case, just remove the mask pieces above.

Lastly, using the maximum case again:

result=MapThread[If[And @@ Positive[{#1, #2}], Max[{#1, #2}], 0] &, {array1, array2},2]


should perform fine, and is simple to change to arbitrary rules/results and easy to understand.

• Thanks a lot, especially for the second part. My arrays are very large. I only gave a small example for the question. – RSG Mar 18 '14 at 10:13
• @rsg: Glad it is useful. Yes, with large arrays, in general doing things "mathematically" as it were tends to be much more efficient. Look for posts by Mr. Wizard, Leonid S., et al for some clever tricks in that arena. Thanks also for accept! – ciao Mar 18 '14 at 10:17

This will zero out the negative entries:

clip = Clip[#, {0, Infinity}] &

rules = Join[Most@ArrayRules@clip[L], Most@ArrayRules@clip[R]];


Warning, the following is undocumented, unsupported, might change in future versions, might blow up your computer, etc.

SetSystemOptions["SparseArrayOptions" -> "TreatRepeatedEntries" -> Max]

SparseArray[rules]

(* set it back *)
SetSystemOptions["SparseArrayOptions" -> "TreatRepeatedEntries" -> First]


Less dangerous:

MaxBy[list_, fun_] := list[[First@Ordering[fun /@ list, -1]]]

SparseArray[MaxBy[#,Last]& /@ GatherBy[rules, First]]


MaxBy is just something I like to use in analogy to SortBy.