我有这个管道,在这里我从Python流数据并以Java应用程序连接到流。数据记录是复数的矩阵。现在,我了解到json.dumps()无法处理pythons复杂类型。
在我将复数值转换为字符串的那一刻,将其放入这样的字典中:
for entry in range(len(data_array)):
data_as_string = [str(i) for i in data_array[entry]["DATA"].tolist()]
send({'data': data_array[entry]["DATA"],
'coords': data_array[entry]["UVW"].tolist()})
并将其发送到管道。但这需要使用Java进行大量昂贵的自定义反序列化,这大大增加了管道的运行时间。 目前,我正在像这样反序列化:
JSONObject = new JSONOBJECT(string);
try {
data= jsonObject.getString("data");
uvw= jsonObject.getString("uvw");
} catch (JSONException ex) {
ex.printStackTrace();
}
然后,我做了很多data.replace(string1, string2)
来删除序列化添加的一些符号,然后循环遍历矩阵以将每个数字转换为Java Complex类型。
我的Java反序列化代码如下所示:
data = data.replace("(","");
data = data.replace(")","");
data = data.replace("\"","");
data = data.replace("],[","¦");
data = data.replace("[","");
data = data.replace("]","");
uvw = uvw.replace("[","");
uvw = uvw.replace("]","");
String[] frequencyArrays = data.split("¦");
Complex[][] tempData = new Complex[48][4];
for(int i=0;i< frequencyArrays.length;i++){
String[] complexNumbersOfAFrequency = frequencyArrays[i].split(", ");
for(int j =0;j<complexNumbersOfAFrequency.length;j++){
boolean realPartNegative = false;
Complex c;
if(complexNumbersOfAFrequency[j].startsWith("-")){
realPartNegative = true;
//Get ridd of the first - sign to be able to split the real & imaginary parts
complexNumbersOfAFrequency[j] =complexNumbersOfAFrequency[j].replaceFirst("-","");
}
if(complexNumbersOfAFrequency[j].contains("+")){
String[] realAndImaginary = complexNumbersOfAFrequency[j].split("\\+");
try {
double real = Double.parseDouble(realAndImaginary[0]);
double imag = Double.parseDouble(realAndImaginary[1].replace("j",""));
if(realPartNegative){
c = new Complex(-real,imag);
} else {
c = new Complex(real,imag);
}
}catch(IndexOutOfBoundsException e) {
//System.out.println("Wrongly formatted number, setting it to 0");
c = new Complex(0,0);
}
catch (NumberFormatException e){
System.out.println("Wrongly formatted number, setting it to 0");
c = new Complex(0,0);
}
} else {
String[] realAndImaginary = complexNumbersOfAFrequency[j].split("-");
try {
double real = Double.parseDouble(realAndImaginary[0]);
double imag = Double.parseDouble(realAndImaginary[1].replace("j", "").replace("e", ""));
if (realPartNegative) {
c = new Complex(-real, -imag);
} else {
c = new Complex(real, -imag);
}
}
catch(IndexOutOfBoundsException e){
System.out.println("Not correctly formatted: ");
for(int temp = 0;temp<realAndImaginary.length;temp++){
System.out.println(realAndImaginary[temp]);
}
System.out.println("Setting it to (0,0)");
c = new Complex(0,0);
}
catch (NumberFormatException e){
c = new Complex(0,0);
}
}
tempData[i][j] = c;
}
}
现在我的问题是是否有办法
1)在Java中反序列化字典,而无需进行昂贵的字符串操作,也无需遍历每个记录或每个记录的矩阵
2)在python中对数据进行序列化方面做得更好,以便可以在Java中更好地完成
任何提示都值得赞赏。
编辑:JSON看起来如下
{"data": ["[(1 + 2j), (3 + 4j), ...]","[(5 + 6j), ...]", ..."],
"coords": [1,2,3]}
编辑:对于坐标,我可以很容易地用Java反序列化:
uvw = uvw.replace("[","");
uvw = uvw.replace("]","");
String[] coords = uvw.split(",");
然后使用coords
将字符串转换成Double.parseDouble()
,但是对于数据字符串来说,这更加复杂,因为字符串中充满了需要删除的字符才能获取实际数字并将它们放在Complex[][]
的正确位置,我想将其投射到
答案 0 :(得分:1)
您正在通过过度使用JsonObject.getString来检索非字符串数据。
让我们从coords
属性开始,因为这是一个简单的案例。 [1,2,3]
不是字符串。它是数字数组。因此,您应该将其检索为数组:
JsonArray coords = jsonObject.getJsonArray("coords");
int count = coords.size();
double[] uvw = new double[count];
for (int i = 0; i < count; i++) {
uvw[i] = coords.getJsonNumber(i).doubleValue();
}
另一个属性data
也是一个数组,但是具有字符串元素:
JsonArray data = jsonObject.getJsonArray("data");
int count = data.size();
for (int i = 0; i < count; i++) {
String complexValuesStr = data.getString(i);
// ...
}
关于解析复数,我不会进行所有这些String.replace调用。相反,您可以使用正则表达式匹配器查找每个复杂值:
Pattern complexNumberPattern = Pattern.compile(
"\\(\\s*" + // opening parenthesis
"(-?[0-9.]+)" + // group 1: match real part
"\\s*([-+])\\s*" + // group 2: match sign
"([0-9.]+)j" + // group 3: match imaginary part
"\\s*\\)"); // closing parenthesis
Matcher matcher = complexNumberPattern.matcher("");
JsonArray data = jsonObject.getJsonArray("data");
int count = data.size();
List<List<Complex>> allFrequencyValues = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
String complexValuesStr = data.getString(i);
List<Complex> singleFrequencyValues = new ArrayList<>();
matcher.reset(complexValuesStr);
while (matcher.find()) {
double real = Double.parseDouble(matcher.group(1));
boolean positive = matcher.group(2).equals("+");
double imaginary = Double.parseDouble(matcher.group(3));
Complex value = new Complex(real, positive ? imaginary : -imaginary);
singleFrequencyValues.add(value);
}
allFrequencyValues.add(singleFrequencyValues);
}
您不应捕获IndexOutOfBoundsException或NumberFormatException。这些表明输入无效。您不应将无效输入视为零。这表示发件人犯了一个错误,您应该确保让他们知道。例外是一种好方法。
我已经假设两个术语始终存在于每个复杂表达式中。例如,2 i 将显示为0 + 2j
,而不仅仅是2j
。像5这样的实数将显示为5 + 0j
。如果这不是一个安全的假设,则解析会变得更加复杂。
由于您担心性能,因此,我会尝试上面的方法;如果使用正则表达式使程序速度太慢,则可以始终通过单步查找字符串来自行查找括号和术语。它将进行更多工作,但可能会提高速度。
答案 1 :(得分:0)
如果我对您的理解正确,那么矩阵将由复数数组组成,而复数数组又将包含实数和虚数。
如果是这样,您的数据可能如下所示:
[[{'r':1,'j':2},{'r':3,'j':4}, ...],[{'r':5,'j':6}, ...]]
这意味着您有一个JSON数组,其中包含包含对象的数组。这些对象具有2个属性:r
定义实数的值和j
虚数的值。
在Java中解析应该是直截了当的,即使用某些映射器(如Jackson或Gson),您只需将其解析为类似ComplexNumber[][]
的地方,其中ComplexNumber
可能看起来像这样(简化):>
public class ComplexNumber {
public double r;
public double j;
}
当然,可能已经存在用于复数的类,因此您可能希望使用它们。另外,您可能必须手动反序列化(因为目标类使映射器不容易使用或者您不想/不希望使用映射器),但是在那种情况下,这只是迭代的问题在JSONArray
元素上,并从r
s中提取j
和JSONObject
。