2

I'm trying to read a file (generated with Fortran) with complex numbers into Python.

Say, after using a = f1.readline().split( ), I get the following value for a:

a = ['(4.471719725275173E-003,2.163649191486555E-002)']

If I do

b = np.complex(a[0])

it produces an error

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-4-cff25069e279> in <module>()
----> 1 b = np.complex(a[0])

ValueError: complex() arg is a malformed string

I tried to do this based on the fact that numpy seems to support Fortran notation (Reading fortran double precision format into python). Is there an equivalent function for complex numbers?

If not, what would be the best way to proceed (rather than using different delimiters in the split( ) call and reconstruct the complex number by hand).

Community
  • 1
  • 1
Nigu
  • 2,025
  • 2
  • 22
  • 31

2 Answers2

2

You can parse it this way (https://stackoverflow.com/a/9763133/721644):

from ast import literal_eval

t = literal_eval(a[0])

b = complex(t[0], t[1])

>(0.004471719725275173+0.02163649191486555j)

It first makes a tuple of floats and than uses its components as arguments to complex().

Community
  • 1
  • 1
1
import numpy as np
a = ['(4.471719725275173E-003,2.163649191486555E-002)']
i, j = np.safe_eval(a[0])

print(np.complex(i, j))
(0.004471719725275173+0.02163649191486555j)

If you are reading from a file and want an array:

import numpy as np



def to_complex(f):
    conv = lambda x: np.complex(*np.safe_eval(x))
    return np.genfromtxt(f, converters={0: conv})

Output:

In [3]: cat out.txt
(4.471719725275173E-003,2.163649191486555E-002)
(6.471719725275173E-003,2.163649191486555E-002)
In [4]: print(to_complex("out.txt"))
[ 0.00447172+0.02163649j  0.00647172+0.02163649j]

Or if you just want a value at a time:

from itertools import imap
def to_complex(f):
    with open(f) as fle:
        for a, b in imap(np.safe_eval, fle):
            yield np.complex(a, b)

Output:

In [7]: print(list(to_complex("out.txt")))
[(0.004471719725275173+0.02163649191486555j), (0.006471719725275173+0.02163649191486555j)]

You could also just cast the data yourself stripping and splitting which would be faster than using safe_eval:

from itertools import imap

def to_complex(f):
    with open(f) as fle:
        for tup in imap(str.strip, fle):
            yield np.complex(*map(float, tup.strip("()").split(",")))

You can use the same logic in with genfromtxt:

from itertools import imap

def to_complex(f):
    conv = lambda x: np.complex(*imap(float, x.strip("()").split(",")))
    return np.genfromtxt(f, converters={0: conv})
Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321