1
$\begingroup$

I have the following list:

[0.312712544956844,
 0.287641445144978 - 0.306854031390629*I,
 0.287641445144978 + 0.306854031390629*I]

I would like to get rid of the complex numbers (both Real & Imaginary parts of them).

I found a very similar answer to that kind of question

list={-1628.12 - 557.34 I, -1628.12 + 557.34 I, -920.324 - 1508.13 I, -920.324 + 1508.13 I, 2107.28, 2145.53, 2207.2, 2289.7,2318.05 - 13.4031 I, 2318.05 + 13.4031 I}

Select[list, Im[#] == 0 &]
#(*{2107.28, 2145.53, 2207.2, 2289.7}*)

When trying these codes I get an invalid syntax error. What would be the reason for that?

Thank you!

$\endgroup$
5
  • 1
    $\begingroup$ How about any of Cases[list, _Real] or Select[list, Head[#] =!= Complex &] or Select[list, # == Re[#] &] // Chop. Is this what you meant? $\endgroup$
    – Moo
    Apr 5, 2022 at 15:07
  • 1
    $\begingroup$ If you're generating complex floating-point numbers, would you consider this real or complex, 1. + 1.*10^-300 I? I would expect round-off error in both the real and imaginary parts. If you know already that you do not have such edge cases as the example, then proceed with Im[#] == 0 and so forth. If you're generating data and need code to handle whatever comes up, then I suggest you need to handle the edge cases in a deliberate way $\endgroup$
    – Michael E2
    Apr 5, 2022 at 15:27
  • $\begingroup$ What do you mean by "when trying these codes"? What exactly did you try? $\endgroup$
    – John Doty
    Apr 5, 2022 at 15:42
  • $\begingroup$ I think @LearningLin's edit fixed the "invalid syntax error." $\endgroup$
    – Michael E2
    Apr 5, 2022 at 18:17
  • 1
    $\begingroup$ Or list /. _Complex :> Nothing $\endgroup$
    – Bob Hanlon
    Apr 5, 2022 at 19:04

2 Answers 2

4
$\begingroup$

There is a very simply and easy to use command: DeleteCases

You can set any condition to be removed from your list:

list={-1628.12 - 557.34 I, -1628.12 + 557.34 I, -920.324 - 1508.13 I, -920.324 + 1508.13 I, 2107.28, 2145.53, 2207.2, 2289.7,2318.05 - 13.4031 I, 2318.05 + 13.4031 I}

Then using it the output would be:

DeleteCases[list, _Complex]

{2107.28,2145.53,2207.2,2289.7}
$\endgroup$
1
$\begingroup$

The OP hasn't returned to the site yet, so I'll give a few ways to test if a number is close enough to be considered real. Equal tests floating-point numbers with relative tolerance (the same up to the last seven bits, usually). So x - y == 0 means x and y are exactly equal, whereas x == y means they agree to 46 bits or more (46 = 53-7), if they are machine precision; and x + y == x means Abs[y] is less than around Abs[x] * 2^7 * $MachineEpsilon if they are machine precision reals. The standard C-like advice on comparing floats is not to use == but something like $|x-y| < t$, for some tolerance $t$ which may depend on $x$ and $y$. In Mathematica, Equal has such a tolerance built in, which one may find convenient, and its design allows it to be used for both exact equality and relative equality.

The tests take advantage of Equal except the last, which is a structural test and not a numeric one. The additional numbers, shown below the divider, show the edge cases of each test.

realTests = {
   Abs[#] == Abs@Re[#] &,
   Re[#] + Im[#] == Re[#] &,
   Im[#] == 0 &,
   Head[#] === Real &}; (* effectively the same as MatchQ[#,_Real]& *)

mydata = {0.312712544956844,
  0.287641445144978 - 0.306854031390629*I,
  0.287641445144978 + 0.306854031390629*I,
  0.287641445144978 + 0.*I,
  0.287641445144978 + $MinMachineNumber*I,
  0.287641445144978 (1 + (2^7 - 1)*$MachineEpsilon/2*I),
  0.287641445144978 (1 + (2^7 - 0)*$MachineEpsilon/2*I),
  0.287641445144978 + ( 2^-24.301)*I,
  0.287641445144978 + ( 2^-24.300)*I};

Grid[
   Join[
     {Prepend[#, ""]},
     Join[Transpose@{mydata}, Through /@ # /@ mydata, 2]] /. 
    True -> Style[True, Darker@Magenta],
   Dividers -> {{False, True, {False}},
               {False, True, False, False, True, {False}}},
   Alignment -> {{Left, {Center}}, Automatic}
   ] &@realTests

These tests may be used in the several selectors of Mathematica:

With[{test = realTests[[2]]},
 Column@{
   Select[mydata, test],
   Pick[mydata, test /@ mydata],
   Cases[mydata, z_?test :> Re[z]]
   }]

Instead of Re[z] in Cases above, you can apply Re to the results to discard the imaginary parts of the selected numbers for any of the tests. Below I also include a particularly efficient method for large data using the vectorization of Im and Sign.

With[{test = realTests[[3]]},
 Column@{
   Re@ Select[mydata, test],
   Re@ Pick[mydata, test /@ mydata],
   Re@ Pick[mydata, Sign@Im@mydata, 0],
   Re@ Cases[mydata, z_?test]
   }]

Exact numbers like 7 and 3 - 2 I behave differently, but consideration of them does not seem within the scope of the question.

$\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.