简体   繁体   English

Java:为未知数量的条目设置数组长度

[英]Java: Setting array length for an unknown number of entries

I am trying to fill a RealVector (from Apache Commons Math) with values. 我正在尝试用值填充RealVector (来自Apache Commons Math)。 I tried using the class's append method, but that didn't actually add anything. 我尝试使用该类的append方法,但实际上并没有添加任何内容。 So now I'm using a double[] , which works fine, except I don't know in advance how big the array needs to be. 因此,现在我使用的是double[] ,它工作正常,但我事先不知道数组需要多大。

private void runAnalysis() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
    Double attr;
    double[] data = new double[100]; // TODO: bad.

    int i = 0;
    for (Method m : ParseTree.class.getMethods()) {
        if (m.isAnnotationPresent(Analyze.class)) {
            attr = (Double) m.invoke(this);
            analysis.put(m.getAnnotation(Analyze.class).name(), attr);
            data[i++] = attr * m.getAnnotation(Analyze.class).weight();
        }
    }

    weightedAnalysis = new ArrayRealVector(data);
}

How can I deal with this issue? 我该如何处理? Here are my ideas: 这是我的想法:

  1. Iterate through the class and count the methods with the annotation, then use that size to initialize the array. 遍历该类并使用批注对方法进行计数,然后使用该大小初始化数组。 However, this will require an extra loop, and reflection is performance-intensive. 但是,这将需要一个额外的循环,并且反射是性能密集的。 (right?) (对?)

  2. Pick an arbitrary size for the array, doubling it if space runs out. 为数组选择任意大小,如果空间用完,则将其加倍。 Downside: requires more lines of code 缺点:需要更多代码行

  3. Use a List<Double> , then somehow weasel the Double objects back into doubles so they can be put in the RealVector . 使用List<Double> ,然后以某种方式将Double对象RealVectordoubles以便可以将它们放入RealVector Uses more memory for the list. 为列表使用更多的内存。

  4. Just pick a huge size for the starting array, and hope that it never overflows. 只需为起始数组选择一个很大的大小,并希望它永远不会溢出。 Downside: this is begging for arrayindexoutofbound errors. 缺点:这是在请求arrayindexoutofbound错误。

  5. Or am I just using append(double d) wrong? 还是我只是使用append(double d)错误?

    private void runAnalysis() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { Double attr; 私有无效runAnalysis()抛出IllegalArgumentException,IllegalAccessException,InvocationTargetException {Double attr; weightedAnalysis = new ArrayRealVector(data); weightedAnalysis =新的ArrayRealVector(data);

     for (Method m : ParseTree.class.getMethods()) { if (m.isAnnotationPresent(Analyze.class)) { attr = (Double) m.invoke(this); analysis.put(m.getAnnotation(Analyze.class).name(), attr); weightedAnalysis.append(attr * m.getAnnotation(Analyze.class).weight()); } } 

    } }

RealVector.append() doesn't modify the vector, but rather constructs a new vector: The [Java doc of RealVector.append()]( http://commons.apache.org/math/apidocs/org/apache/commons/math/linear/RealVector.html#append(double)) explains: RealVector.append()不会修改矢量,而是构造一个新的矢量:[RealVector.append()的Java文档]( http://commons.apache.org/math/apidocs/org/apache/commons /math/linear/RealVector.html#append(double))解释:

append

RealVector append(double d)
Construct a vector by appending a double to this vector.
Parameters:
d - double to append.
Returns:
a new vector

Please note that using RealVector to construct the vector is quite an expensive operation, as append() would need to copy the elements over and over (ie constructing the array in the way you explained runs in O(n^2) time. 请注意,使用RealVector构造向量是一个非常昂贵的操作,因为append()将需要一遍又一遍地复制元素(即,按照您解释的方式在O(n^2)时间内构造数组O(n^2)

I would recommend simply using java's ArrayList<Double> during construction, and then simply converting to RealVector or any other data abstraction you like. 我建议仅在构造过程中使用java的ArrayList<Double> ,然后简单地转换为RealVector或您喜欢的任何其他数据抽象。

为什么不使用ArrayList并向其中添加元素?

I would suggest 3 as a good option. 我建议将3作为一个不错的选择。 Using Double vs double is a minimal problem since autoboxing was introduced. 由于引入了自动装箱,因此使用Double vs Double是一个最小的问题。

Using RealVector will take a huge amount of memory and computation time to build, because what you want is: 使用RealVector会花费大量的内存和计算时间,因为您想要的是:

RealVector newVector = oldVector.append(d);

append() returns a newly constructed object, which is what you'd want for correctness. append()返回一个新构造的对象,这就是您想要的正确性。

If you're okay with heavy overhead on build, take a look at Apache Commons ArrayUtils , specifically add(double) and/or toPrimitive(Double). 如果您可以在构建上承担大量开销,可以看看Apache Commons ArrayUtils ,特别是add(double)和/或toPrimitive(Double)。

You mentioned that you tried the append method, but that didn't actually add anything. 您提到您尝试了append方法,但实际上并没有添加任何内容。 After looking at the javadoc, make sure that you assign the result of the append method back to the original value...You probably already tried this, but just in case you overlooked: 查看完Javadoc之后,请确保将append方法的结果分配回原始值...您可能已经尝试过此操作,但以防万一您忽略了:

RealVector myRealVector = new ArrayRealVector(data);
myRealVector = myRealVector.append(1.0);

in other words, this won't change myRealVector: 换句话说,这不会更改myRealVector:

RealVector myRealVector = new ArrayRealVector(data);
myRealVector.append(1.0);

you could initialize the array using the 您可以使用来初始化数组

ParseTree.class.getMethods().lenght

as initial capacity: 作为初始容量:

double[] buf = new double[ ParseTree.class.getMethods().lenght ];

or better 或更好

DoubleBuffer buf = DoubleBuffer.allocate([ ParseTree.class.getMethods().lenght);

this may waste some memory but is a safe solution, it depends on how many hit the if inside the loop has. 这可能会浪费一些内存,但这是一个安全的解决方案,它取决于循环中是否命中了多少个。

if you prefer you may count how many methods are annotated in advance and then allocate the exact size for the array 如果愿意,可以预先计算要注释的方法数量,然后为数组分配确切的大小

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM