Java 8复杂自定义收集器

Java 8复杂自定义收集器,java,java-8,java-stream,Java,Java 8,Java Stream,我有一个对象流,我想收集以下方式 假设我们正在处理论坛帖子: class Post { private Date time; private Data data } 我想创建一个列表,按时段对帖子进行分组。如果X分钟内没有帖子,请创建新组 class PostsGroup{ List<Post> posts = new ArrayList<> (); } 我想获得一个组中的帖子列表: [ {posts : [{time:x, data:{}}

我有一个对象流,我想收集以下方式

假设我们正在处理论坛帖子:

class Post {
    private Date time;
    private Data data
}
我想创建一个列表,按时段对帖子进行分组。如果X分钟内没有帖子,请创建新组

class PostsGroup{
    List<Post> posts = new ArrayList<> ();
}
我想获得一个组中的帖子列表:

[
 {posts : [{time:x, data:{}}, {time:x + 3, data:{}}, {time:x+ 12, data:{}]]},
{posts : [{time:x+ 45, data:{}]}
]
  • 请注意,第一组持续到X+22。然后在X+45收到一个新的邮件

这可能吗?

您需要保留流条目之间的状态,并为自己编写一个分组分类器。像这样的事情将是一个好的开始

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;
    }

}
class Post{
私人最终很长时间;
私有最终字符串数据;
公共帖子(长时间,字符串数据){
这个时间=时间;
这个数据=数据;
}
@凌驾
公共字符串toString(){
返回“Post{“+”time=“+time+”,data=“+data+'}”;
}
}
公开无效测试(){
System.out.println(“你好”);
长t=0;
List posts=Arrays.asList(
新职位(t,“一”),
新员额(t+1000,“两个”),
新员额(t+10 000,“三个”)
);
//每5秒分组一次。
地图被挖出=柱子
.stream()
.collect(Collectors.groupingBy(新分类BYTimebetween(5000));
gouped.entrySet().stream().forEach((e)->{
System.out.println(e.getKey()+“->”+e.getValue());
});
}
类ClassifyByTimeBetween实现函数{
最终长延时;
长currentGroupBy=-1;
long lastDateSeen=-1;
公共分类ByTimeBetween(长延迟){
延迟=延迟;
}
@凌驾
公开长期申请(p职位){
如果(lastDateSeen>=0){
如果(p.time>lastDateSeen+延迟){
//抓住这个。
currentGroupBy=p.time;
}
}否则{
//第一次-从那里开始。
currentGroupBy=p.time;
}
lastDateSeen=p.time;
返回当前GroupBy;
}
}

使用my library的方法可以轻松解决此问题:

long MAX_INTERVAL=TimeUnit.MINUTES.toMillis(10);
第十条(员额)

.groupRuns((p1,p2)->p2.time.getTime()-p1.time.getTime()您可以通过调用Day.getTime()将日期时间转换为long,该函数以毫秒为单位返回long。您还可以将10分钟转换为毫秒,毫秒应为10*60*1000。现在在Day.getTime()上放置一些比较逻辑以查找下一个10分钟条目。
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;
    }

}
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;
    }
}