1
$\begingroup$

I have a column vector of the form $\{1, 1, 2, 3, 2, 3\}^t$ and an associated matrix that has the same number of rows as the column vector, $6$, and a number of columns that is equal to the maximum of the values in the vector, $3$.

I would like to construct a matrix that has a specific value at the positions $\{1, 1\}, \{2, 1\}, \{3, 2\}, \{4,3\}, \{5,2\}, \{6, 3\}$ and zeroes everywhere else, that is, the row index corresponds to the row index in the column vector and the column index corresponds to the value at that row index.

A solution using a loop is clear to me, is there also a nifty Mathematica trick that does the job?

$\endgroup$
4
  • $\begingroup$ Flatten /@ Transpose[{Range@Length@cv, cv}] or Partition[Riffle[Range@Length@cv, Flatten@cv] , 2] where cv is your column vector will give you the desired positions list. $\endgroup$
    – ciao
    Jun 15, 2014 at 21:49
  • $\begingroup$ Thanks for your comment, but note that I do not want to construct a matrix of the form {1,1},{2,1},{3,2},{4,3},{5,2},{6,3}, but a matrix that has a specific value at these positions and the rest zeroes. I edited the question to clarify. $\endgroup$ Jun 15, 2014 at 22:03
  • $\begingroup$ I got that, but since you said nothing about the target matrix (and still really haven't), I left that to you. Do you mean by "associated" that the target matrix is same # of rows, and has # cols equal to max value of the CV? $\endgroup$
    – ciao
    Jun 15, 2014 at 22:07
  • $\begingroup$ Yes, that would be correct. The "smaller than" part was completely wrong, I edited it out. The target matrix has the dimensions you mention and is filled with zeros. $\endgroup$ Jun 15, 2014 at 22:11

2 Answers 2

4
$\begingroup$
(* make some col vec *)
cv = Transpose[{{1, 1, 2, 3, 2, 3}}]

(*Use it to fill positions in associated array with e.g. twos *)    
result=Normal@SparseArray[
    Flatten /@ Transpose[{Range@Length@#, #}] -> #2, {Length@#, Max@#}] &[cv, 2]

(* {{2, 0, 0}, {2, 0, 0}, {0, 2, 0}, {0, 0, 2}, {0, 2, 0}, {0, 0, 2}} *)

You could also just create the appropriately dimensioned zero array, then use something like ReplacePart to replace desired positions with the value, but I find the SparseArray approach cleaner, and if your arrays are large with mostly zeroes, keeping it sparse (don't Normal@ it) will save you considerable space to boot...

$\endgroup$
1
  • $\begingroup$ Thanks, that is exactly what I was looking for. $\endgroup$ Jun 15, 2014 at 22:12
1
$\begingroup$

Another variation using SparseArray:

ClearAll[saF];
saF= SparseArray[MapIndexed[{First@#2, #} &, #1] -> #2, ##3] & 

cols = {1, 1, 2, 3, 2, 3};
saF[cols, a] //Normal
(* {{a, 0, 0}, {a, 0, 0}, {0, a, 0}, {0, 0, a}, {0, a, 0}, {0, 0, a}}   *)

saF[cols, {a, b, c, d, e, f}] // Normal
(*  {{a, 0, 0}, {b, 0, 0}, {0, c, 0}, {0, 0, d}, {0, e, 0}, {0, 0, f}}  *)

saF[cols, a, Automatic, b] // Normal
(* {{a, b, b}, {a, b, b}, {b, a, b}, {b, b, a}, {b, a, b}, {b, b, a}}  *)

saF[cols, a, {6, 6}] // Normal
(* {{a, 0, 0, 0, 0, 0}, {a, 0, 0, 0, 0, 0}, {0, a, 0, 0, 0, 0}, 
    {0, 0, a, 0, 0, 0}, {0, a, 0, 0, 0, 0}, {0, 0, a, 0, 0, 0}}  *)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.