Java 8流组条目通过数字邻近度

时间:2016-02-01 13:22:55

标签: java java-8 java-stream

我有一个unix时间戳列表,例如:

[1111111 1200000 1200060 1200120 1200180 1300000 1400000 140060]

我想将它们按照彼此间隔60秒的簇进行分组,其中键是第一个时间戳,例如:

{1111111=[1111111], 1200000=[1200000,120060, 1200120], 1300000=[1300000], 1400060=[1400000, 1400060]} 

我通过使用for循环实现了这一点,我希望有一种更好的方法来实现这一点,最好使用Java 8流。

(我对Java不太好,所以如果没有办法使用流,那么构建for循环是否更好?)

List <Integer> timestamps = new ArrayList<Integer>();
timestamps.add(1111111);
timestamps.add(1200000);
timestamps.add(1200060);
timestamps.add(1200120);
timestamps.add(1200180);
timestamps.add(1300000);
timestamps.add(1400000);
timestamps.add(1400060);

HashMap <Integer, List <Integer>> grouped = new HashMap<Integer, List <Integer>>();

List <Integer> subList = new ArrayList<Integer>();

for (int i = 0; i < timestamps.size(); i++) {
  if(i > 0 && (timestamps.get(i - 1) + 60 < timestamps.get(i))) {
        grouped.put(subList.get(0), new ArrayList <Integer>(subList));
        subList.removeAll(subList);
   }
   subList.add(timestamps.get(i));  
}
grouped.put(subList.get(0), subList);

1 个答案:

答案 0 :(得分:5)

为了执行此操作,您需要对匹配谓词的Stream上的连续元素进行操作。遗憾的是,目前没有标准方法可以轻松实现Stream API。

StreamEx库为此工具提供groupRuns操作。考虑到列表已经排序(否则,您可以通过调用sorted()对其进行排序),您可以:

Map<Integer, List<Integer>> map =
    StreamEx.of(timestamps)
            .groupRuns((t1, t2) -> t2 - t1 <= 60)
            .toMap(l -> l.get(0), l -> l);

您问题中的数据结果:

{1200000=[1200000, 1200060, 1200120, 1200180], 1300000=[1300000], 1400000=[1400000, 1400060], 1111111=[1111111]}

方法groupRuns对与给定谓词匹配的所有连续元素进行分组,并默认将所有这些元素收集到List中。在这种情况下,列表的第一个元素将是最终Map的键,列表本身将是值。