A fast way to compute arrays avoiding If or Which
As a complement to Anon's answer you can use pattern based rules in SparseArray
, but depending on the pattern it may not be fast. (It will still have the memory advantage of a sparse array). For example:
SparseArray[{i_, j:(1|3|5)} :> 2*i + j, {2, 5}] // MatrixForm
$\left( \begin{array}{ccccc} 3 & 0 & 5 & 0 & 7 \\ 5 & 0 & 7 & 0 & 9 \end{array} \right)$
If neither answer is applicable please try to clarify the question.
Alright, so your $j$ indexes are dependent on a function of the $i$ index. You could do this with Condition
as follows, but performance will be poor. At the very least memoize the index function:
f[n_] := f[n] = Mod[Multinomial[Range@3, n], 5, 1]
SparseArray[{i_, j_} /; MemberQ[f@i, j] :> 2*i + j, {3, 5}] // MatrixForm
$\left( \begin{array}{ccccc} 0 & 4 & 5 & 6 & 0 \\ 5 & 0 & 7 & 0 & 9 \\ 0 & 0 & 0 & 10 & 11 \end{array} \right)$
It would be better to build a position list as Anon described in a comment. Here is a more complete example:
SparseArray[
{##} -> 2 # + #2 & @@@ Join @@ Array[Thread@{#, f@#} &, 3]
] // MatrixForm
$\left( \begin{array}{ccccc} 0 & 4 & 5 & 6 & 0 \\ 5 & 0 & 7 & 0 & 9 \\ 0 & 0 & 0 & 10 & 11 \end{array} \right)$
In a somewhat different style for use with listable inner functions (the 2*i + j
part):
is = Join @@ (ConstantArray[Range@3, 3]\[Transpose])
js = Join @@ Array[f, 3]
SparseArray[Thread[{is, js}] -> 2 is + js] // MatrixForm
{1, 1, 1, 2, 2, 2, 3, 3, 3} {2, 3, 4, 3, 1, 5, 4, 5, 5}
$\left( \begin{array}{ccccc} 0 & 4 & 5 & 6 & 0 \\ 5 & 0 & 7 & 0 & 9 \\ 0 & 0 & 0 & 10 & 11 \end{array} \right)$
In example B you know the different indices, i.e. you know the positions of the elements. If you know the positions of the elements, you can use SparseArray
:
SparseArray[Rule[#, 2 #[[1]] + #[[2]]] & /@ Tuples[{{1, 2}, {1, 3, 5}}]] // MatrixForm
(*(3 0 5 0 7
5 0 7 0 9)*)
If you want to create a PackedArray, rather than a SparseArray
object, the following is an option
cfu =
Compile[
{{list, _Integer, 1}, {nn, _Integer}}
,
Block[
{max = Max[list], len = Length[list], res}
,
res = ConstantArray[0, {nn, max}];
Do[
If[
list[[ll]] == j
,
res[[i, j]] = 2*i + j
]
,
{i, 1, nn},
{j, 1, max},
{ll, 1, len}
];
res
]
]
example
cfu[{1, 3, 5}, 2] // MatrixForm
(*output*)
(*(3 0 5 0 7
5 0 7 0 9)*)
The result is indeed a PackedArray
<<Developer`
PackedArrayQ@cfu[Range[1000], 3]
True