7
$\begingroup$

I have a list of associations keyed by real and imaginary numbers, like so:

matrix = {
   {<|"r" -> 0.368252, "i" -> 0.0199587|>, 
    <|"r" -> -0.461644, "i" -> 0.109868|>, 
    <|"r" -> -0.216081, "i" -> 0.562557|>, 
    <|"r" -> -0.479881, "i" -> -0.212978|>}, 

   {<|"r" -> 0.105028, "i" -> 0.632264|>, 
    <|"r" -> 0.116589, "i" -> -0.490063|>, 
    <|"r" -> 0.463378, "i" -> 0.231656|>,
    <|"r" -> -0.148665, "i" -> 0.212065|>},

   {<|"r" -> 0.463253, "i" -> 0.201161|>,
    <|"r" -> 0.460547, "i" -> 0.397829|>,
    <|"r" -> 0.222257, "i" -> 0.0129121|>,
    <|"r" -> 0.168641, "i" -> -0.544568|>},

   {<|"r" -> 0.255221, "i" -> -0.364687|>,
    <|"r" -> 0.191895, "i" -> -0.337437|>,
    <|"r" -> -0.12278, "i" -> 0.551195|>,
    <|"r" -> 0.560485, "i" -> 0.134702|>}
}

Given this, I can write

testmatrix = Join[Values[matrix], 2]`

to get a matrix, but it is a matrix of tuples. How can I get the complex number defined in each <|r -> Re[z], i -> Im[z]|> rather than the tuples?

$\endgroup$

3 Answers 3

5
$\begingroup$

I'm a bit uncomfortable with both @HenrikSchumacher's and @kglr's (first) answers, as they rely on the correct sorting order of the keys in the Associations: they assume that every matrix element is precisely of the form of an association with first the "r" part and second the "i" part.

Without relying on the sorting order, or on the presence of both elements, and making more use of the essential features of associations, we can do

matrix /. a_Association :> Lookup[a, {"r", "i"}, 0].{1, I}

This solution works even if one matrix element is of the form <|"r" -> 2|> or <|"i" -> -3|> (it will default the other coordinate to zero). It also works if the order of the elements is interchanged: <|"r" -> 2, "i" -> -3|> gives the same result as <|"i" -> -3, "r" -> 2|>. It also works on higher-dimensional tensors or ragged structures.

$\endgroup$
10
$\begingroup$
Join[Values[matrix], 2].{1, I}

As J.M. pointed out, this can even be shortened to the following:

Values[matrix].{1, I}

A nice feature of this approach is that it produces packed arrays when possible.

$\endgroup$
1
  • 1
    $\begingroup$ Even better: Values[matrix].{1, I}, which preserves the matrix structure. $\endgroup$ Commented Mar 4, 2019 at 0:53
9
$\begingroup$
Apply[Complex, matrix, {2}] (* or *)
Map[{#r, #i}.{1, I} &, matrix, {2}]

{{0.368252 +0.0199587 I,-0.461644+0.109868 I,-0.216081+0.562557 I,-0.479881-0.212978 I},
{0.105028 +0.632264 I,0.116589 -0.490063 I,0.463378 +0.231656 I,-0.148665+0.212065 I},
{0.463253 +0.201161 I,0.460547 +0.397829 I,0.222257 +0.0129121 I,0.168641 -0.544568 I},
{0.255221 -0.364687 I,0.191895 -0.337437 I,-0.12278+0.551195 I,0.560485 +0.134702 I}}

$\endgroup$
4
  • $\begingroup$ Huh, that's a great one! A word of warning though: This method produces unpacked arrays. $\endgroup$ Commented Mar 3, 2019 at 23:48
  • $\begingroup$ The Apply[Complex] method will also fail if the entries are not integers or inexact real numbers, e.g. Complex @@ {Pi, Sqrt[2]}. $\endgroup$ Commented Mar 4, 2019 at 0:55
  • $\begingroup$ @J.M.iscomputer-less and Henrik, thank you both. Added an alternative version using Map + Dot. $\endgroup$
    – kglr
    Commented Mar 4, 2019 at 17:44
  • 1
    $\begingroup$ If you Apply or Map these at level {-2} instead of {2}, then these methods will work for vectors and higher-dimensional tensors as well. $\endgroup$
    – Roman
    Commented Mar 5, 2019 at 14:43

Your Answer

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

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