我有一个对象流,我想按以下方式收集。
我们说我们正在处理论坛帖子:
class Post {
private Date time;
private Data data
}
我想创建一个按期间对帖子进行分组的列表。如果X分钟没有帖子,请创建新组。
class PostsGroup{
List<Post> posts = new ArrayList<> ();
}
我希望得到一个List<PostGroups>
,其中包含按时间间隔分组的帖子。
示例:间隔10分钟。
帖子:
[{time:x, data:{}}, {time:x + 3, data:{}} , {time:x+ 12, data:{}, {time:x + 45, data:{}}}]
我想获得一个帖子组列表:
[
{posts : [{time:x, data:{}}, {time:x + 3, data:{}}, {time:x+ 12, data:{}]]},
{posts : [{time:x+ 45, data:{}]}
]
这可能吗?
答案 0 :(得分:2)
使用groupRuns
库的StreamEx方法可以轻松解决此问题:
long MAX_INTERVAL = TimeUnit.MINUTES.toMillis(10);
StreamEx.of(posts)
.groupRuns((p1, p2) -> p2.time.getTime() - p1.time.getTime() <= MAX_INTERVAL)
.map(PostsGroup::new)
.toList();
我假设你有一个构造函数
class PostsGroup {
private List<Post> posts;
public PostsGroup(List<Post> posts) {
this.posts = posts;
}
}
StreamEx.groupRuns
方法采用BiPredicate
,它应用于两个相邻的输入元素,如果必须将它们组合在一起,则返回true。此方法创建列表流,其中每个列表代表该组。这种方法很懒惰,并行使用并行流。
答案 1 :(得分:0)
您需要在流条目之间保留状态,并为自己编写分组分类器。这样的事情将是一个良好的开端。
class Post {
private final long time;
private final String data;
public Post(long time, String data) {
this.time = time;
this.data = data;
}
@Override
public String toString() {
return "Post{" + "time=" + time + ", data=" + data + '}';
}
}
public void test() {
System.out.println("Hello");
long t = 0;
List<Post> posts = Arrays.asList(
new Post(t, "One"),
new Post(t + 1000, "Two"),
new Post(t + 10000, "Three")
);
// Group every 5 seconds.
Map<Long, List<Post>> gouped = posts
.stream()
.collect(Collectors.groupingBy(new ClassifyByTimeBetween(5000)));
gouped.entrySet().stream().forEach((e) -> {
System.out.println(e.getKey() + " -> " + e.getValue());
});
}
class ClassifyByTimeBetween implements Function<Post, Long> {
final long delay;
long currentGroupBy = -1;
long lastDateSeen = -1;
public ClassifyByTimeBetween(long delay) {
this.delay = delay;
}
@Override
public Long apply(Post p) {
if (lastDateSeen >= 0) {
if (p.time > lastDateSeen + delay) {
// Grab this one.
currentGroupBy = p.time;
}
} else {
// First time - start there.
currentGroupBy = p.time;
}
lastDateSeen = p.time;
return currentGroupBy;
}
}