是否有一种 Java 数据结构实际上是具有双索引和内置插值的 ArrayList?
我正在寻找具有以下特征的预构建 Java 数据结构:
它应该看起来像 ArrayList,但应该允许通过双精度而不是整数进行索引。请注意,这意味着您可能会看到与原始数据点不相符的索引(即要求与键“1.5”对应的值)。 编辑:为了清楚起见,根据评论,我不打算更改 ArrayList 实现。我正在寻找类似的界面和开发人员体验。
因此,返回的值可能会被插值。例如,如果键为 1.5,则返回的值可能是键 1.0 处的值和键 2.0 处的值的平均值。
键将被排序,但值不保证单调递增。事实上,无法保证值的一阶导数是连续的(使其不太适合某些类型的样条线)。
仅提供免费代码。
为了清楚起见,我知道如何写这样的东西。事实上,我们已经在遗留代码中实现了这个和一些相关的数据结构,由于一些性能和编码问题,我想替换它们。
我试图避免的是花费大量时间来滚动我自己的解决方案,而 JDK,Apache Commons或另一个标准库。坦率地说,这正是使这些遗留代码陷入现在困境的方法......
免费提供的库中有这样的东西吗?
I am looking for a pre-built Java data structure with the following characteristics:
It should look something like an ArrayList but should allow indexing via double-precision rather than integers. Note that this means that it's likely that you'll see indicies that don't line up with the original data points (i.e., asking for the value that corresponds to key "1.5"). EDIT: For clarity, based on the comments, I'm not looking to change the ArrayList implementation. I'm looking for a similar interface and developer experience.
As a consequence, the value returned will likely be interpolated. For example, if the key is 1.5, the value returned could be the average of the value at key 1.0 and the value at key 2.0.
The keys will be sorted but the values are not ensured to be monotonically increasing. In fact, there's no assurance that the first derivative of the values will be continuous (making it a poor fit for certain types of splines).
Freely available code only, please.
For clarity, I know how to write such a thing. In fact, we already have an implementation of this and some related data structures in legacy code that I want to replace due to some performance and coding issues.
What I'm trying to avoid is spending a lot of time rolling my own solution when there might already be such a thing in the JDK, Apache Commons or another standard library. Frankly, that's exactly the approach that got this legacy code into the situation that it's in right now....
Is there such a thing out there in a freely available library?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
允许
double
值作为索引是对ArrayList
所做的相当大的改变。这样做的原因是,以
double
作为索引的数组或列表几乎根据定义是 稀疏数组,这意味着它对于几乎所有可能的索引没有值(或者取决于您的定义:固定的已知值),并且只有有限数量的索引具有显式值集。Java SE 中没有预构建的类支持所有这些。
就我个人而言,我会实现这样一个数据结构:skip-list(或类似的具有适当插值的(索引,值)
元组的快速搜索数据结构。编辑:实际上,后端存储有一个非常好的匹配(即除了插值之外的所有内容):只需使用 < code>NavigableMap 例如
TreeMap
存储从索引到值的映射。这样您就可以轻松使用 < code>ceilingEntry() 和(如有必要)
higherEntry()
获取最接近您需要的索引的值,然后从中进行插值。Allowing
double
values as indices is a pretty large change from whatArrayList
does.The reason for this is that an array or list with
double
as indices would almost by definition be a sparse array, which means it has no value (or depending on your definition: a fixed, known value) for almost all possible indices and only a finite number of indices have an explicit value set.There is no prebuilt class in Java SE that supports all that.
Personally I'd implement such a data structure as a skip-list (or similar fast-searching data structure) of(index, value)
tuples with appropriate interpolation.Edit: Actually there's a pretty good match for the back-end storage (i.e. everything except for the interpolation): Simply use a
NavigableMap
such as aTreeMap
to store the mapping from index to value.With that you can easily use
ceilingEntry()
and (if necessary)higherEntry()
to get the closest value(s) to the index you need and then interpolate from those.如果您当前的实现插入值的复杂度为 O(log N),那么我刚刚编写的实现可能适合您:
具体的插值器只需实现
get(double)
函数。例如:
最后,进行单元测试:
所以该功能似乎可以工作。我只测量了一些简单情况下的速度,这些表明缩放会比线性更好。
更新 (2010-10-17T23:45+0200): 我在检查
LinearInterpolator
中的key
参数时犯了一些愚蠢的错误,我的单元测试没有发现它们。现在我扩展了测试并相应地修复了代码。If your current implementation has complexity O(log N) for interpolating a value, the implementation I just made up may be for you:
The concrete interpolators will only have to implement the
get(double)
function.For example:
And, finally, a unit test:
So the functionality seems to work. I only measured speed in some simple cases, and these suggest that scaling will be better than linear.
Update (2010-10-17T23:45+0200): I made some stupid mistakes in checking the
key
argument in theLinearInterpolator
, and my unit tests didn't catch them. Now I extended the tests and fixed the code accordingly.在 Apache commons-math 库中,如果您实现 UnivariateRealInterpolator 及其 interpolate 方法的返回值(输入 < a href="http://commons.apache.org/math/api-2.0/org/apache/commons/math/analysis/UnivariateRealFunction.html" rel="nofollow">UnivariateRealFunction 你会最那里的路。
插值器接口采用两个数组:x[] 和 y[]。返回的函数有一个方法 value(),它接受 x' 并返回插值后的 y'。
它无法提供类似 ArrayList 的体验的地方在于能够向范围和域添加更多值,就像 列表 正在增长。
此外,他们似乎需要一些额外的插值函数。稳定版本库中只有 4 个实现。正如评论者指出的那样,它似乎缺少“线性”或更简单的东西,例如最近邻居。也许这不是真正的插值......
In the Apache commons-math library, if you implement the UnivariateRealInterpolator and the return value of its interpolate method which is typed UnivariateRealFunction you'll be most of the way there.
The interpolator interface takes two arrays, x[] and y[]. The returned function has a method, value() that takes an x' and returns the interpolated y'.
Where it fails to provide an ArrayList-like experience is in the ability to add more values to the range and domain as if the List is growing.
Additionally, they look to be in need of some additional interpolation functions. There are only 4 implementations in the library for the stable release. As a commenter pointed out, it seems to be missing 'linear' or something even simpler like nearest neighbor. Maybe that's not really interpolation...
这是与 ArrayList 相比的巨大变化。
与上面 Joachim 的响应相同,但我可能会将其实现为二叉树,当我没有找到我正在寻找的东西时,对下一个最小值和最大值的值进行平均,这应该可以快速遍历到。
That's a huge change from ArrayList.
Same as Joachim's response above, but I'd probably implement this as a binary tree, and when I didn't find something I was looking for, average the value of the next smallest and largest values, which should be quick to traverse to.
您关于它应该“像 ArrayList”的描述具有误导性,因为您所描述的是一维插值器,并且本质上与 ArrayList 没有任何共同点。这就是为什么您会收到有关其他数据结构的建议,而 IMO 却将您引向了错误的道路。
我不知道 Java 中有任何可用的(并且无法轻松找到一一谷歌),但我认为您应该看看 GSL - GNU 科学库 其中包括 样条插值器。对于您正在寻找的东西来说,它可能有点重,因为它是一个二维插值器,但似乎您应该寻找这样的东西,而不是像 ArrayList 这样的东西。
如果您希望它“看起来像 ArrayList”,您始终可以将其包装在 Java 类中,该类具有与 List 接口类似的访问方法。但您将无法实际实现该接口,因为这些方法被声明为采用整数索引。
Your description that it should be "like an ArrayList" is misleading, since what you've described is a one dimensional interpolator and has essentially nothing in common with an ArrayList. This is why you're getting suggestions for other data structures which IMO are sending you down the wrong path.
I don't know of any available in Java (and couldn't easily find one one google), but I think you should have a look at GSL - GNU Scientific Library which includes a spline interpolator. It may be a bit heavy for what you're looking for since it's a two dimensional interpolator, but it seems like you should be looking for something like this rather than something like an ArrayList.
If you'd like it to "look like an ArrayList" you can always wrap it in a Java class which has access methods similar to the List interface. You won't be able to actually implement the interface though, since the methods are declared to take integer indices.