如何使用Java8进行分组和收集?

如何使用Java8进行分组和收集?,java,java-8,java-stream,Java,Java 8,Java Stream,我有一个元素列表,我们称之为关键字,如下所示: public class Keyword { Long id; String name; String owner; Date createdTime; Double price; Date metricDay; Long position; } public class KeywordMetric { Double price; Date metricDay; Lo

我有一个元素列表,我们称之为关键字,如下所示:

public class Keyword {
    Long id;
    String name;
    String owner;
    Date createdTime;
    Double price;
    Date metricDay;
    Long position;
}
public class KeywordMetric {
    Double price;
    Date metricDay;
    Long position;
} 
public class KeywordMeged {
    Long id;
    String name;
    String owner;
    List<KeywordMetric> metricList;
}
public class KeywordMerged {
    public static KeywordMerged from(Keyword k) {            
        KeywordMetric metric = new KeywordMetric();
        metric.setPrice(k.getPrice());
        metric.setMetricDay(k.getMetricDay());
        metric.setPosition(k.getPosition());

        KeywordMerged merged = new KeywordMerged();
        merged.setId(k.getId());
        merged.setName(k.getName());
        merged.setOwner(k.getOwner());
        merged.setMetricList(new ArrayList<>(Arrays.asList(metric)));
        return merged;
    }
}
问题是每一天都有一个关键词。例如:

Keyword{id=1, name="kw1", owner="Josh", createdTime="12/12/1992", price="0.1", metricDay="11/11/1999", position=109}
Keyword{id=1, name="kw1", owner="Josh", createdTime="12/12/1992", price="0.3", metricDay="12/11/1999", position=108}
Keyword{id=1, name="kw1", owner="Josh", createdTime="12/12/1992", price="0.2", metricDay="13/11/1999", position=99}
Keyword{id=2, name="kw2", owner="Josh", createdTime="13/12/1992", price="0.6", metricDay="13/11/1999", position=5}
Keyword{id=2, name="kw2", owner="Josh", createdTime="13/12/1992", price="0.1", metricDay="14/11/1999", position=4}
Keyword{id=3, name="kw3", owner="Josh", createdTime="13/12/1992", price="0.1", metricDay="13/11/1999", position=8}
然后,从这个列表中,我想创建一个新的列表,在一个列表中包含所有这些不同日期的所有指标。首先,我创建了这样一个类:

public class Keyword {
    Long id;
    String name;
    String owner;
    Date createdTime;
    Double price;
    Date metricDay;
    Long position;
}
public class KeywordMetric {
    Double price;
    Date metricDay;
    Long position;
} 
public class KeywordMeged {
    Long id;
    String name;
    String owner;
    List<KeywordMetric> metricList;
}
public class KeywordMerged {
    public static KeywordMerged from(Keyword k) {            
        KeywordMetric metric = new KeywordMetric();
        metric.setPrice(k.getPrice());
        metric.setMetricDay(k.getMetricDay());
        metric.setPosition(k.getPosition());

        KeywordMerged merged = new KeywordMerged();
        merged.setId(k.getId());
        merged.setName(k.getName());
        merged.setOwner(k.getOwner());
        merged.setMetricList(new ArrayList<>(Arrays.asList(metric)));
        return merged;
    }
}
我想归档的是从第一个列表到如下结构:

public class Keyword {
    Long id;
    String name;
    String owner;
    Date createdTime;
    Double price;
    Date metricDay;
    Long position;
}
public class KeywordMetric {
    Double price;
    Date metricDay;
    Long position;
} 
public class KeywordMeged {
    Long id;
    String name;
    String owner;
    List<KeywordMetric> metricList;
}
public class KeywordMerged {
    public static KeywordMerged from(Keyword k) {            
        KeywordMetric metric = new KeywordMetric();
        metric.setPrice(k.getPrice());
        metric.setMetricDay(k.getMetricDay());
        metric.setPosition(k.getPosition());

        KeywordMerged merged = new KeywordMerged();
        merged.setId(k.getId());
        merged.setName(k.getName());
        merged.setOwner(k.getOwner());
        merged.setMetricList(new ArrayList<>(Arrays.asList(metric)));
        return merged;
    }
}
我知道如何处理大量循环和可变变量,但我不知道如何处理流和lambda操作。我能够通过Id对所有相关关键字进行分组:

Map<Long, List<Keyword>> kwL = kwList.stream()
                    .collect(groupingBy(Keyword::getId))
我知道使用.forEach我可以迭代该映射,但不知道如何使流的collect方法从List传递到KeywordMerged

您可以尝试改用。其中:

关键字::getId是一个键映射器函数

关键字合并。从。。。执行转换:关键字=>KeywordMerged

{}对于左->实体,使用相同的ID组合

Collection<KeywordMerged> result = keywords.stream()
    .collect(Collectors.toMap(
        Keyword::getId,
        k -> KeywordMerged.from(k), // you can replace this lambda with a method reference
        (left, right) -> {
            left.getMetricList().addAll(right.getMetricList());
            return left;
        }))
    .values();
转换方法可能如下所示:

public class Keyword {
    Long id;
    String name;
    String owner;
    Date createdTime;
    Double price;
    Date metricDay;
    Long position;
}
public class KeywordMetric {
    Double price;
    Date metricDay;
    Long position;
} 
public class KeywordMeged {
    Long id;
    String name;
    String owner;
    List<KeywordMetric> metricList;
}
public class KeywordMerged {
    public static KeywordMerged from(Keyword k) {            
        KeywordMetric metric = new KeywordMetric();
        metric.setPrice(k.getPrice());
        metric.setMetricDay(k.getMetricDay());
        metric.setPosition(k.getPosition());

        KeywordMerged merged = new KeywordMerged();
        merged.setId(k.getId());
        merged.setName(k.getName());
        merged.setOwner(k.getOwner());
        merged.setMetricList(new ArrayList<>(Arrays.asList(metric)));
        return merged;
    }
}
我想你已经有了基本的想法。因此,根据您的需要进行重构…

您可以尝试使用。其中:

关键字::getId是一个键映射器函数

关键字合并。从。。。执行转换:关键字=>KeywordMerged

左、右->{..}组合具有相同ID的实体的度量

Collection<KeywordMerged> result = keywords.stream()
    .collect(Collectors.toMap(
        Keyword::getId,
        k -> KeywordMerged.from(k), // you can replace this lambda with a method reference
        (left, right) -> {
            left.getMetricList().addAll(right.getMetricList());
            return left;
        }))
    .values();
转换方法可能如下所示:

public class Keyword {
    Long id;
    String name;
    String owner;
    Date createdTime;
    Double price;
    Date metricDay;
    Long position;
}
public class KeywordMetric {
    Double price;
    Date metricDay;
    Long position;
} 
public class KeywordMeged {
    Long id;
    String name;
    String owner;
    List<KeywordMetric> metricList;
}
public class KeywordMerged {
    public static KeywordMerged from(Keyword k) {            
        KeywordMetric metric = new KeywordMetric();
        metric.setPrice(k.getPrice());
        metric.setMetricDay(k.getMetricDay());
        metric.setPosition(k.getPosition());

        KeywordMerged merged = new KeywordMerged();
        merged.setId(k.getId());
        merged.setName(k.getName());
        merged.setOwner(k.getOwner());
        merged.setMetricList(new ArrayList<>(Arrays.asList(metric)));
        return merged;
    }
}

我想你已经有了基本的想法。因此,根据您的需要进行重构…

这是一种稍微不同的方法。首先,收集按id分组的关键字图:

Map<Integer, List<Keyword>> groupedData = keywords.stream()
    .collect(Collectors.groupingBy(k -> k.getId()));
进一步将地图转换为所需格式的列表:

List<KeywordMerged> finalData = groupedData.entrySet().stream()
    .map(k -> new KeywordMerged(k.getValue().get(0).getId(),
        k.getValue().stream()
            .map(v -> new KeywordMetric(v.getMetricDay(), v.getPrice(), getPosition()))
            .collect(Collectors.toList())))
    .collect(Collectors.toList());
这将对分组数据起作用,但转换映射将创建KeywordMerged对象,该对象作为参数将接收id,您可以自己进一步扩展它,并转换为以前按id分组的列表数据


编辑:我相信通过一些提取方法,你可以使它看起来更漂亮:

一个稍微不同的方法。首先,收集按id分组的关键字图:

Map<Integer, List<Keyword>> groupedData = keywords.stream()
    .collect(Collectors.groupingBy(k -> k.getId()));
进一步将地图转换为所需格式的列表:

List<KeywordMerged> finalData = groupedData.entrySet().stream()
    .map(k -> new KeywordMerged(k.getValue().get(0).getId(),
        k.getValue().stream()
            .map(v -> new KeywordMetric(v.getMetricDay(), v.getPrice(), getPosition()))
            .collect(Collectors.toList())))
    .collect(Collectors.toList());
这将对分组数据起作用,但转换映射将创建KeywordMerged对象,该对象作为参数将接收id,您可以自己进一步扩展它,并转换为以前按id分组的列表数据


编辑:我相信通过一些提取方法,你可以让它看起来更好:

有什么想法吗?是的,但是你试过什么?看起来你想让我们为你写一些代码。虽然许多用户愿意为陷入困境的程序员编写代码,但他们通常只在海报已经试图自己解决问题时才提供帮助。演示这项工作的一个好方法是包括您迄今为止编写的代码、示例输入(如果有)、预期输出以及您实际获得的控制台输出、回溯等。。你提供的细节越多,你可能得到的答案就越多。检查并更新我的问题,我没有走得太远,这就是为什么我没有把我的代码。谢谢你的建议,有什么想法吗?是的,但是你试过什么?看起来你想让我们为你写一些代码。虽然许多用户愿意为陷入困境的程序员编写代码,但他们通常只在海报已经试图自己解决问题时才提供帮助。演示这项工作的一个好方法是包括您迄今为止编写的代码、示例输入(如果有)、预期输出以及您实际获得的控制台输出、回溯等。。你提供的细节越多,你可能得到的答案就越多。检查并更新我的问题,我没有走得太远,这就是为什么我没有把我的代码。谢谢你的建议。