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