Java在集合中查找最接近(或相等)的值

时间:2011-05-10 15:52:49

标签: java collections find predicate

我有一个类:

public class Observation {
   private String time;
   private double x;
   private double y;

   //Constructors + Setters + Getters
}

我可以选择将这些对象存储在任何类型的集合中(标准类或第三方像Guava)。我已经在下面的ArrayList中存储了一些示例数据,但就像我说的那样,我对任何其他类型的集合都是开放的。所以,一些示例数据:

ArrayList<Observation> ol = new ArrayList<Observation>();
ol.add(new Observation("08:01:23",2.87,3.23));
ol.add(new Observation("08:01:27",2.96,3.17));
ol.add(new Observation("08:01:27",2.93,3.20));
ol.add(new Observation("08:01:28",2.93,3.21));
ol.add(new Observation("08:01:30",2.91,3.23));

该示例假定Observation中的匹配构造函数。时间戳存储为String个对象,因为我从外部源接收它们,但我很乐意将它们转换为其他内容。我按时间顺序接收观察结果,因此我可以创建并依赖于有序的观察集合。时间戳不是唯一的(如示例数据中所示),因此我无法基于time创建唯一键。

现在问题。我经常需要找到一个time等于或接近某个时间的观察,例如,如果我的时间是08:01:29我想在示例数据中获取第四个观察值,如果时间是08:01:27我想要第3次观察。

我显然可以遍历整个集合,直到找到我正在寻找的时间,但我需要经常这样做,并且在一天结束时我可能有数百万的观察,所以我需要找到一个解决方案可以有效地找到相关的观察结果。

我已经查看了各种集合类型,包括我可以使用Predicates过滤集合的集合类型,但我找不到可以返回一个值的解决方案,而不是满足该集合的集合的子集。 “&LT; =” - 状态。我基本上在寻找SELECT * FROM ol WHERE time <= t LIMIT 1的SQL等价物。

我确信有一种聪明而简单的方法可以解决我的问题所以我希望能够开悟。提前谢谢。

4 个答案:

答案 0 :(得分:10)

尝试使用TreeSet提供比较时间的比较器。它保留了一个有序的集合,你可以要求TreeSet.floor(E)找到最大的分钟(你应该提供一个虚拟观察与你正在寻找的时间)。您还可以为有序子集设置headSet和tailSet。

添加和检索时间为O(log n)。我认为非常适合您的需求。

如果您更喜欢Map,可以使用类似方法的TreeMap。

答案 1 :(得分:4)

Observation类实现Comparable并使用TreeSet来存储对象,这将保持元素的排序。 TreeSet实施SortedSet,因此您可以使用headSettailSet在您要搜索的元素之前或之后获取该集合的视图。使用返回集上的firstlast方法获取您正在寻找的元素。

如果您遇到ArrayList,但可以自行对元素进行排序,请使用Collections.binarySearch搜索元素。如果找到确切的元素,则返回正数,或者可以使用负数来确定最接近的元素。 http://download.oracle.com/javase/1.4.2/docs/api/java/util/Collections.html#binarySearch(java.util.List,%20java.lang.Object

答案 2 :(得分:3)

对你的集合进行排序(ArrayList在这里可能效果最好)并使用BinarySearch返回一个“最接近”可能匹配的匹配的整数索引,即返回...

  

搜索关键字的索引,如果它包含在列表中;否则,( - (插入点) - 1)。插入点定义为键将插入列表的点:第一个元素的索引大于键,或list.size(),

答案 3 :(得分:1)

如果你有幸使用Java 6,那么保持SortedSet的性能开销对你来说不是什么大问题。请查看TreeSet ceilingfloorhigherlower方法。